client_test.go 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package client
  4. import (
  5. "bytes"
  6. "encoding/json"
  7. "io"
  8. "net/http"
  9. "reflect"
  10. "testing"
  11. "time"
  12. )
  13. type roundTripperFunc func(req *http.Request) (*http.Response, error)
  14. func (fn roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
  15. return fn(req)
  16. }
  17. func newFakeHTTPClient(
  18. t *testing.T,
  19. fn func(t *testing.T, req *http.Request) *http.Response,
  20. ) *http.Client {
  21. return &http.Client{
  22. Transport: roundTripperFunc(
  23. func(req *http.Request) (*http.Response, error) {
  24. return fn(t, req), nil
  25. }),
  26. }
  27. }
  28. func jsonResponseFrom(
  29. t *testing.T,
  30. status int,
  31. headers http.Header,
  32. body any,
  33. ) *http.Response {
  34. data, err := json.Marshal(body)
  35. if err != nil {
  36. t.Fatalf("Unable to marshal body: %v", err)
  37. }
  38. return &http.Response{
  39. StatusCode: status,
  40. Body: io.NopCloser(bytes.NewBuffer(data)),
  41. Header: headers,
  42. }
  43. }
  44. func asJSON(data any) string {
  45. json, err := json.MarshalIndent(data, "", " ")
  46. if err != nil {
  47. panic(err)
  48. }
  49. return string(json)
  50. }
  51. func expectRequest(
  52. t *testing.T,
  53. method string,
  54. url string,
  55. checkBody func(r io.Reader),
  56. req *http.Request,
  57. ) {
  58. if req.Method != method {
  59. t.Fatalf("Expected method to be %s, got %s", method, req.Method)
  60. }
  61. if req.URL.String() != url {
  62. t.Fatalf("Expected URL path to be %s, got %s", url, req.URL)
  63. }
  64. if checkBody != nil {
  65. checkBody(req.Body)
  66. }
  67. }
  68. func expectFromJSON[T any](
  69. t *testing.T,
  70. r io.Reader,
  71. expected *T,
  72. ) {
  73. var got T
  74. if err := json.NewDecoder(r).Decode(&got); err != nil {
  75. t.Fatalf("Expected no error, got %v", err)
  76. }
  77. if !reflect.DeepEqual(&got, expected) {
  78. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(got))
  79. }
  80. }
  81. func TestHealthcheck(t *testing.T) {
  82. client := NewClientWithOptions(
  83. "http://mf",
  84. WithHTTPClient(
  85. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  86. expectRequest(t, http.MethodGet, "http://mf/healthcheck", nil, req)
  87. return &http.Response{
  88. StatusCode: http.StatusOK,
  89. Body: io.NopCloser(bytes.NewBufferString("OK")),
  90. }
  91. })))
  92. if err := client.HealthcheckContext(t.Context()); err != nil {
  93. t.Fatalf("Expected no error, got %v", err)
  94. }
  95. }
  96. func TestVersion(t *testing.T) {
  97. expected := &VersionResponse{
  98. Version: "1.0.0",
  99. Commit: "1234567890",
  100. BuildDate: "2021-01-01T00:00:00Z",
  101. GoVersion: "go1.20",
  102. Compiler: "gc",
  103. Arch: "amd64",
  104. OS: "linux",
  105. }
  106. client := NewClientWithOptions(
  107. "http://mf",
  108. WithHTTPClient(
  109. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  110. expectRequest(t, http.MethodGet, "http://mf/v1/version", nil, req)
  111. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  112. })))
  113. res, err := client.VersionContext(t.Context())
  114. if err != nil {
  115. t.Fatalf("Expected no error, got %v", err)
  116. }
  117. if !reflect.DeepEqual(res, expected) {
  118. t.Fatalf("Expected %+v, got %+v", expected, res)
  119. }
  120. }
  121. func TestMe(t *testing.T) {
  122. expected := &User{
  123. ID: 1,
  124. Username: "test",
  125. Password: "password",
  126. IsAdmin: false,
  127. Theme: "light",
  128. Language: "en",
  129. Timezone: "UTC",
  130. EntryDirection: "asc",
  131. EntryOrder: "created_at",
  132. Stylesheet: "default",
  133. CustomJS: "custom.js",
  134. GoogleID: "google-id",
  135. OpenIDConnectID: "openid-connect-id",
  136. EntriesPerPage: 10,
  137. KeyboardShortcuts: true,
  138. ShowReadingTime: true,
  139. EntrySwipe: true,
  140. GestureNav: "horizontal",
  141. DisplayMode: "read",
  142. DefaultReadingSpeed: 1,
  143. CJKReadingSpeed: 1,
  144. DefaultHomePage: "home",
  145. CategoriesSortingOrder: "asc",
  146. MarkReadOnView: true,
  147. MediaPlaybackRate: 1.0,
  148. BlockFilterEntryRules: "block",
  149. KeepFilterEntryRules: "keep",
  150. ExternalFontHosts: "https://fonts.googleapis.com",
  151. AlwaysOpenExternalLinks: true,
  152. OpenExternalLinksInNewTab: true,
  153. }
  154. client := NewClientWithOptions(
  155. "http://mf",
  156. WithHTTPClient(
  157. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  158. expectRequest(t, http.MethodGet, "http://mf/v1/me", nil, req)
  159. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  160. })))
  161. res, err := client.MeContext(t.Context())
  162. if err != nil {
  163. t.Fatalf("Expected no error, got %v", err)
  164. }
  165. if !reflect.DeepEqual(res, expected) {
  166. t.Fatalf("Expected %+v, got %+v", expected, res)
  167. }
  168. }
  169. func TestUsers(t *testing.T) {
  170. expected := Users{
  171. {
  172. ID: 1,
  173. Username: "test1",
  174. },
  175. {
  176. ID: 2,
  177. Username: "test2",
  178. },
  179. }
  180. client := NewClientWithOptions(
  181. "http://mf",
  182. WithHTTPClient(
  183. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  184. expectRequest(t, http.MethodGet, "http://mf/v1/users", nil, req)
  185. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  186. })))
  187. res, err := client.UsersContext(t.Context())
  188. if err != nil {
  189. t.Fatalf("Expected no error, got %v", err)
  190. }
  191. if !reflect.DeepEqual(res, expected) {
  192. t.Fatalf("Expected %+v, got %+v", expected, res)
  193. }
  194. }
  195. func TestUserByID(t *testing.T) {
  196. expected := &User{
  197. ID: 1,
  198. Username: "test",
  199. }
  200. client := NewClientWithOptions(
  201. "http://mf",
  202. WithHTTPClient(
  203. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  204. expectRequest(t, http.MethodGet, "http://mf/v1/users/1", nil, req)
  205. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  206. })))
  207. res, err := client.UserByIDContext(t.Context(), 1)
  208. if err != nil {
  209. t.Fatalf("Expected no error, got %v", err)
  210. }
  211. if !reflect.DeepEqual(res, expected) {
  212. t.Fatalf("Expected %+v, got %+v", expected, res)
  213. }
  214. }
  215. func TestUserByUsername(t *testing.T) {
  216. expected := &User{
  217. ID: 1,
  218. Username: "test",
  219. }
  220. client := NewClientWithOptions(
  221. "http://mf",
  222. WithHTTPClient(
  223. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  224. expectRequest(t, http.MethodGet, "http://mf/v1/users/test", nil, req)
  225. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  226. })))
  227. res, err := client.UserByUsernameContext(t.Context(), "test")
  228. if err != nil {
  229. t.Fatalf("Expected no error, got %v", err)
  230. }
  231. if !reflect.DeepEqual(res, expected) {
  232. t.Fatalf("Expected %+v, got %+v", expected, res)
  233. }
  234. }
  235. func TestCreateUser(t *testing.T) {
  236. expected := &User{
  237. ID: 1,
  238. Username: "test",
  239. Password: "password",
  240. IsAdmin: true,
  241. }
  242. client := NewClientWithOptions(
  243. "http://mf",
  244. WithHTTPClient(
  245. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  246. exp := UserCreationRequest{
  247. Username: "test",
  248. Password: "password",
  249. IsAdmin: true,
  250. }
  251. expectRequest(
  252. t,
  253. http.MethodPost,
  254. "http://mf/v1/users",
  255. func(r io.Reader) {
  256. expectFromJSON(t, r, &exp)
  257. },
  258. req)
  259. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  260. })))
  261. res, err := client.CreateUserContext(t.Context(), "test", "password", true)
  262. if err != nil {
  263. t.Fatalf("Expected no error, got %v", err)
  264. }
  265. if !reflect.DeepEqual(res, expected) {
  266. t.Fatalf("Expected %+v, got %+v", expected, res)
  267. }
  268. }
  269. func TestUpdateUser(t *testing.T) {
  270. expected := &User{
  271. ID: 1,
  272. Username: "test",
  273. Password: "password",
  274. IsAdmin: true,
  275. }
  276. client := NewClientWithOptions(
  277. "http://mf",
  278. WithHTTPClient(
  279. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  280. expectRequest(t, http.MethodPut, "http://mf/v1/users/1", func(r io.Reader) {
  281. expectFromJSON(t, r, &UserModificationRequest{
  282. Username: &expected.Username,
  283. Password: &expected.Password,
  284. })
  285. }, req)
  286. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  287. })))
  288. res, err := client.UpdateUserContext(t.Context(), 1, &UserModificationRequest{
  289. Username: &expected.Username,
  290. Password: &expected.Password,
  291. })
  292. if err != nil {
  293. t.Fatalf("Expected no error, got %v", err)
  294. }
  295. if !reflect.DeepEqual(res, expected) {
  296. t.Fatalf("Expected %+v, got %+v", expected, res)
  297. }
  298. }
  299. func TestDeleteUser(t *testing.T) {
  300. client := NewClientWithOptions(
  301. "http://mf",
  302. WithHTTPClient(
  303. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  304. expectRequest(t, http.MethodDelete, "http://mf/v1/users/1", nil, req)
  305. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  306. })))
  307. if err := client.DeleteUserContext(t.Context(), 1); err != nil {
  308. t.Fatalf("Expected no error, got %v", err)
  309. }
  310. }
  311. func TestAPIKeys(t *testing.T) {
  312. expected := APIKeys{
  313. {
  314. ID: 1,
  315. Token: "token",
  316. Description: "test",
  317. },
  318. {
  319. ID: 2,
  320. Token: "token2",
  321. Description: "test2",
  322. },
  323. }
  324. client := NewClientWithOptions(
  325. "http://mf",
  326. WithHTTPClient(
  327. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  328. expectRequest(t, http.MethodGet, "http://mf/v1/api-keys", nil, req)
  329. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  330. })))
  331. res, err := client.APIKeysContext(t.Context())
  332. if err != nil {
  333. t.Fatalf("Expected no error, got %v", err)
  334. }
  335. if !reflect.DeepEqual(res, expected) {
  336. t.Fatalf("Expected %+v, got %+v", expected, res)
  337. }
  338. }
  339. func TestCreateAPIKey(t *testing.T) {
  340. expected := &APIKey{
  341. ID: 42,
  342. Token: "some-token",
  343. Description: "desc",
  344. }
  345. client := NewClientWithOptions(
  346. "http://mf",
  347. WithHTTPClient(
  348. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  349. expectRequest(t, http.MethodPost, "http://mf/v1/api-keys", func(r io.Reader) {
  350. expectFromJSON(t, r, &APIKeyCreationRequest{
  351. Description: "desc",
  352. })
  353. }, req)
  354. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  355. })))
  356. res, err := client.CreateAPIKeyContext(t.Context(), "desc")
  357. if err != nil {
  358. t.Fatalf("Expected no error, got %v", err)
  359. }
  360. if !reflect.DeepEqual(res, expected) {
  361. t.Fatalf("Expected %+v, got %+v", expected, res)
  362. }
  363. }
  364. func TestDeleteAPIKey(t *testing.T) {
  365. client := NewClientWithOptions(
  366. "http://mf",
  367. WithHTTPClient(
  368. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  369. expectRequest(t, http.MethodDelete, "http://mf/v1/api-keys/1", nil, req)
  370. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  371. })))
  372. if err := client.DeleteAPIKeyContext(t.Context(), 1); err != nil {
  373. t.Fatalf("Expected no error, got %v", err)
  374. }
  375. }
  376. func TestMarkAllAsRead(t *testing.T) {
  377. client := NewClientWithOptions(
  378. "http://mf",
  379. WithHTTPClient(
  380. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  381. expectRequest(t, http.MethodPut, "http://mf/v1/users/1/mark-all-as-read", nil, req)
  382. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  383. })))
  384. if err := client.MarkAllAsReadContext(t.Context(), 1); err != nil {
  385. t.Fatalf("Expected no error, got %v", err)
  386. }
  387. }
  388. func TestIntegrationsStatus(t *testing.T) {
  389. client := NewClientWithOptions(
  390. "http://mf",
  391. WithHTTPClient(
  392. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  393. expectRequest(t, http.MethodGet, "http://mf/v1/integrations/status", nil, req)
  394. return jsonResponseFrom(t, http.StatusOK, http.Header{}, struct {
  395. HasIntegrations bool `json:"has_integrations"`
  396. }{
  397. HasIntegrations: true,
  398. })
  399. })))
  400. status, err := client.IntegrationsStatusContext(t.Context())
  401. if err != nil {
  402. t.Fatalf("Expected no error, got %v", err)
  403. }
  404. if !status {
  405. t.Fatalf("Expected integrations status to be true, got false")
  406. }
  407. }
  408. func TestDiscover(t *testing.T) {
  409. expected := Subscriptions{
  410. {
  411. URL: "http://example.com",
  412. Title: "Example",
  413. Type: "rss",
  414. },
  415. }
  416. client := NewClientWithOptions(
  417. "http://mf",
  418. WithHTTPClient(
  419. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  420. expectRequest(t, http.MethodPost, "http://mf/v1/discover", func(r io.Reader) {
  421. expectFromJSON(t, r, &map[string]string{"url": "http://example.com"})
  422. }, req)
  423. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  424. })))
  425. res, err := client.DiscoverContext(t.Context(), "http://example.com")
  426. if err != nil {
  427. t.Fatalf("Expected no error, got %v", err)
  428. }
  429. if !reflect.DeepEqual(res, expected) {
  430. t.Fatalf("Expected %+v, got %+v", expected, res)
  431. }
  432. }
  433. func TestCategories(t *testing.T) {
  434. expected := Categories{
  435. {
  436. ID: 1,
  437. Title: "Example",
  438. },
  439. }
  440. client := NewClientWithOptions(
  441. "http://mf",
  442. WithHTTPClient(
  443. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  444. expectRequest(t, http.MethodGet, "http://mf/v1/categories", nil, req)
  445. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  446. })))
  447. res, err := client.CategoriesContext(t.Context())
  448. if err != nil {
  449. t.Fatalf("Expected no error, got %v", err)
  450. }
  451. if !reflect.DeepEqual(res, expected) {
  452. t.Fatalf("Expected %+v, got %+v", expected, res)
  453. }
  454. }
  455. func TestCategoriesWithCounters(t *testing.T) {
  456. feedCount := 1
  457. totalUnread := 2
  458. expected := Categories{
  459. {
  460. ID: 1,
  461. Title: "Example",
  462. FeedCount: &feedCount,
  463. TotalUnread: &totalUnread,
  464. },
  465. }
  466. client := NewClientWithOptions(
  467. "http://mf",
  468. WithHTTPClient(
  469. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  470. expectRequest(t, http.MethodGet, "http://mf/v1/categories?counts=true", nil, req)
  471. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  472. })))
  473. res, err := client.CategoriesWithCountersContext(t.Context())
  474. if err != nil {
  475. t.Fatalf("Expected no error, got %v", err)
  476. }
  477. if !reflect.DeepEqual(res, expected) {
  478. t.Fatalf("Expected %+v, got %+v", expected, res)
  479. }
  480. }
  481. func TestCreateCategory(t *testing.T) {
  482. expected := &Category{
  483. ID: 1,
  484. Title: "Example",
  485. }
  486. client := NewClientWithOptions(
  487. "http://mf",
  488. WithHTTPClient(
  489. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  490. expectRequest(t, http.MethodPost, "http://mf/v1/categories", func(r io.Reader) {
  491. expectFromJSON(t, r, &CategoryCreationRequest{
  492. Title: "Example",
  493. })
  494. }, req)
  495. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  496. })))
  497. res, err := client.CreateCategoryContext(t.Context(), "Example")
  498. if err != nil {
  499. t.Fatalf("Expected no error, got %v", err)
  500. }
  501. if !reflect.DeepEqual(res, expected) {
  502. t.Fatalf("Expected %+v, got %+v", expected, res)
  503. }
  504. }
  505. func TestCreateCategoryWithOptions(t *testing.T) {
  506. expected := &Category{
  507. ID: 1,
  508. Title: "Example",
  509. HideGlobally: true,
  510. }
  511. client := NewClientWithOptions(
  512. "http://mf",
  513. WithHTTPClient(
  514. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  515. expectRequest(t, http.MethodPost, "http://mf/v1/categories", func(r io.Reader) {
  516. expectFromJSON(t, r, &CategoryCreationRequest{
  517. Title: "Example",
  518. HideGlobally: true,
  519. })
  520. }, req)
  521. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  522. })))
  523. res, err := client.CreateCategoryWithOptionsContext(t.Context(), &CategoryCreationRequest{
  524. Title: "Example",
  525. HideGlobally: true,
  526. })
  527. if err != nil {
  528. t.Fatalf("Expected no error, got %v", err)
  529. }
  530. if !reflect.DeepEqual(res, expected) {
  531. t.Fatalf("Expected %+v, got %+v", expected, res)
  532. }
  533. }
  534. func TestUpdateCategory(t *testing.T) {
  535. expected := &Category{
  536. ID: 1,
  537. Title: "Example",
  538. }
  539. client := NewClientWithOptions(
  540. "http://mf",
  541. WithHTTPClient(
  542. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  543. expectRequest(t, http.MethodPut, "http://mf/v1/categories/1", func(r io.Reader) {
  544. expectFromJSON(t, r, &CategoryModificationRequest{
  545. Title: &expected.Title,
  546. })
  547. }, req)
  548. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  549. })))
  550. res, err := client.UpdateCategoryContext(t.Context(), 1, "Example")
  551. if err != nil {
  552. t.Fatalf("Expected no error, got %v", err)
  553. }
  554. if !reflect.DeepEqual(res, expected) {
  555. t.Fatalf("Expected %+v, got %+v", expected, res)
  556. }
  557. }
  558. func TestUpdateCategoryWithOptions(t *testing.T) {
  559. expected := &Category{
  560. ID: 1,
  561. Title: "Example",
  562. HideGlobally: true,
  563. }
  564. client := NewClientWithOptions(
  565. "http://mf",
  566. WithHTTPClient(
  567. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  568. expectRequest(t, http.MethodPut, "http://mf/v1/categories/1", func(r io.Reader) {
  569. expectFromJSON(t, r, &CategoryModificationRequest{
  570. Title: &expected.Title,
  571. HideGlobally: &expected.HideGlobally,
  572. })
  573. }, req)
  574. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  575. })))
  576. res, err := client.UpdateCategoryWithOptionsContext(t.Context(), 1, &CategoryModificationRequest{
  577. Title: &expected.Title,
  578. HideGlobally: &expected.HideGlobally,
  579. })
  580. if err != nil {
  581. t.Fatalf("Expected no error, got %v", err)
  582. }
  583. if !reflect.DeepEqual(res, expected) {
  584. t.Fatalf("Expected %+v, got %+v", expected, res)
  585. }
  586. }
  587. func TestMarkCategoryAsRead(t *testing.T) {
  588. client := NewClientWithOptions(
  589. "http://mf",
  590. WithHTTPClient(
  591. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  592. expectRequest(t, http.MethodPut, "http://mf/v1/categories/1/mark-all-as-read", nil, req)
  593. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  594. })))
  595. if err := client.MarkCategoryAsReadContext(t.Context(), 1); err != nil {
  596. t.Fatalf("Expected no error, got %v", err)
  597. }
  598. }
  599. func TestCategoryFeeds(t *testing.T) {
  600. expected := Feeds{
  601. {
  602. ID: 1,
  603. Title: "Example",
  604. },
  605. }
  606. client := NewClientWithOptions(
  607. "http://mf",
  608. WithHTTPClient(
  609. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  610. expectRequest(t, http.MethodGet, "http://mf/v1/categories/1/feeds", nil, req)
  611. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  612. })))
  613. res, err := client.CategoryFeedsContext(t.Context(), 1)
  614. if err != nil {
  615. t.Fatalf("Expected no error, got %v", err)
  616. }
  617. if !reflect.DeepEqual(res, expected) {
  618. t.Fatalf("Expected %+v, got %+v", expected, res)
  619. }
  620. }
  621. func TestDeleteCategory(t *testing.T) {
  622. client := NewClientWithOptions(
  623. "http://mf",
  624. WithHTTPClient(
  625. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  626. expectRequest(t, http.MethodDelete, "http://mf/v1/categories/1", nil, req)
  627. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  628. })))
  629. if err := client.DeleteCategoryContext(t.Context(), 1); err != nil {
  630. t.Fatalf("Expected no error, got %v", err)
  631. }
  632. }
  633. func TestRefreshCategory(t *testing.T) {
  634. client := NewClientWithOptions(
  635. "http://mf",
  636. WithHTTPClient(
  637. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  638. expectRequest(t, http.MethodPut, "http://mf/v1/categories/1/refresh", nil, req)
  639. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  640. })))
  641. if err := client.RefreshCategoryContext(t.Context(), 1); err != nil {
  642. t.Fatalf("Expected no error, got %v", err)
  643. }
  644. }
  645. func TestFeeds(t *testing.T) {
  646. expected := Feeds{
  647. {
  648. ID: 1,
  649. Title: "Example",
  650. FeedURL: "http://example.com",
  651. SiteURL: "http://example.com",
  652. CheckedAt: time.Date(1970, 1, 1, 0, 7, 0, 0, time.UTC),
  653. Disabled: false,
  654. IgnoreHTTPCache: false,
  655. AllowSelfSignedCertificates: false,
  656. FetchViaProxy: false,
  657. ScraperRules: "",
  658. RewriteRules: "",
  659. UrlRewriteRules: "",
  660. BlocklistRules: "",
  661. KeeplistRules: "",
  662. BlockFilterEntryRules: "",
  663. KeepFilterEntryRules: "",
  664. Crawler: false,
  665. UserAgent: "",
  666. Cookie: "",
  667. Username: "",
  668. Password: "",
  669. Category: &Category{
  670. ID: 1,
  671. Title: "Example",
  672. },
  673. HideGlobally: false,
  674. DisableHTTP2: false,
  675. ProxyURL: "",
  676. },
  677. {
  678. ID: 2,
  679. Title: "Example 2",
  680. },
  681. }
  682. client := NewClientWithOptions(
  683. "http://mf",
  684. WithHTTPClient(
  685. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  686. expectRequest(t, http.MethodGet, "http://mf/v1/feeds", nil, req)
  687. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  688. })))
  689. res, err := client.FeedsContext(t.Context())
  690. if err != nil {
  691. t.Fatalf("Expected no error, got %v", err)
  692. }
  693. if !reflect.DeepEqual(res, expected) {
  694. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  695. }
  696. }
  697. func TestExport(t *testing.T) {
  698. expected := []byte("hello")
  699. client := NewClientWithOptions(
  700. "http://mf",
  701. WithHTTPClient(
  702. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  703. expectRequest(t, http.MethodGet, "http://mf/v1/export", nil, req)
  704. return &http.Response{
  705. StatusCode: http.StatusOK,
  706. Body: io.NopCloser(bytes.NewBufferString(string(expected))),
  707. Header: http.Header{},
  708. }
  709. })))
  710. res, err := client.ExportContext(t.Context())
  711. if err != nil {
  712. t.Fatalf("Expected no error, got %v", err)
  713. }
  714. if !reflect.DeepEqual(res, expected) {
  715. t.Fatalf("Expected %+v, got %+v", expected, res)
  716. }
  717. }
  718. func TestImport(t *testing.T) {
  719. expected := []byte("hello")
  720. client := NewClientWithOptions(
  721. "http://mf",
  722. WithHTTPClient(
  723. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  724. expectRequest(
  725. t,
  726. http.MethodPost,
  727. "http://mf/v1/import",
  728. func(r io.Reader) {
  729. b, err := io.ReadAll(r)
  730. if err != nil {
  731. t.Fatalf("Expected no error, got %v", err)
  732. }
  733. if !bytes.Equal(b, expected) {
  734. t.Fatalf("expected %+v, got %+v", expected, b)
  735. }
  736. },
  737. req)
  738. return &http.Response{
  739. StatusCode: http.StatusOK,
  740. Header: http.Header{},
  741. }
  742. })))
  743. if err := client.ImportContext(t.Context(), io.NopCloser(bytes.NewBufferString(string(expected)))); err != nil {
  744. t.Fatalf("Expected no error, got %v", err)
  745. }
  746. }
  747. func TestFeed(t *testing.T) {
  748. expected := &Feed{
  749. ID: 1,
  750. Title: "Example",
  751. }
  752. client := NewClientWithOptions(
  753. "http://mf",
  754. WithHTTPClient(
  755. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  756. expectRequest(t, http.MethodGet, "http://mf/v1/feeds/1", nil, req)
  757. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  758. })))
  759. res, err := client.FeedContext(t.Context(), 1)
  760. if err != nil {
  761. t.Fatalf("Expected no error, got %v", err)
  762. }
  763. if !reflect.DeepEqual(res, expected) {
  764. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  765. }
  766. }
  767. func TestCreateFeed(t *testing.T) {
  768. client := NewClientWithOptions(
  769. "http://mf",
  770. WithHTTPClient(
  771. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  772. expectRequest(t, http.MethodPost, "http://mf/v1/feeds", nil, req)
  773. return jsonResponseFrom(t, http.StatusOK, http.Header{}, struct {
  774. FeedID int64 `json:"feed_id"`
  775. }{
  776. FeedID: 1,
  777. })
  778. })))
  779. id, err := client.CreateFeedContext(t.Context(), &FeedCreationRequest{
  780. FeedURL: "http://example.com",
  781. })
  782. if err != nil {
  783. t.Fatalf("Expected no error, got %v", err)
  784. }
  785. if id != 1 {
  786. t.Fatalf("Expected feed ID to be 1, got %d", id)
  787. }
  788. }
  789. func TestUpdateFeed(t *testing.T) {
  790. expected := &Feed{
  791. ID: 1,
  792. FeedURL: "http://example.com/",
  793. }
  794. client := NewClientWithOptions(
  795. "http://mf",
  796. WithHTTPClient(
  797. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  798. expectRequest(t, http.MethodPut, "http://mf/v1/feeds/1", nil, req)
  799. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  800. })))
  801. res, err := client.UpdateFeedContext(t.Context(), 1, &FeedModificationRequest{
  802. FeedURL: &expected.FeedURL,
  803. })
  804. if err != nil {
  805. t.Fatalf("Expected no error, got %v", err)
  806. }
  807. if !reflect.DeepEqual(res, expected) {
  808. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  809. }
  810. }
  811. func TestMarkFeedAsRead(t *testing.T) {
  812. client := NewClientWithOptions(
  813. "http://mf",
  814. WithHTTPClient(
  815. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  816. expectRequest(t, http.MethodPut, "http://mf/v1/feeds/1/mark-all-as-read", nil, req)
  817. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  818. })))
  819. if err := client.MarkFeedAsReadContext(t.Context(), 1); err != nil {
  820. t.Fatalf("Expected no error, got %v", err)
  821. }
  822. }
  823. func TestRefreshAllFeeds(t *testing.T) {
  824. client := NewClientWithOptions(
  825. "http://mf",
  826. WithHTTPClient(
  827. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  828. expectRequest(t, http.MethodPut, "http://mf/v1/feeds/refresh", nil, req)
  829. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  830. })))
  831. if err := client.RefreshAllFeedsContext(t.Context()); err != nil {
  832. t.Fatalf("Expected no error, got %v", err)
  833. }
  834. }
  835. func TestRefreshFeed(t *testing.T) {
  836. client := NewClientWithOptions(
  837. "http://mf",
  838. WithHTTPClient(
  839. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  840. expectRequest(t, http.MethodPut, "http://mf/v1/feeds/1/refresh", nil, req)
  841. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  842. })))
  843. if err := client.RefreshFeedContext(t.Context(), 1); err != nil {
  844. t.Fatalf("Expected no error, got %v", err)
  845. }
  846. }
  847. func TestDeleteFeed(t *testing.T) {
  848. client := NewClientWithOptions(
  849. "http://mf",
  850. WithHTTPClient(
  851. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  852. expectRequest(t, http.MethodDelete, "http://mf/v1/feeds/1", nil, req)
  853. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  854. })))
  855. if err := client.DeleteFeedContext(t.Context(), 1); err != nil {
  856. t.Fatalf("Expected no error, got %v", err)
  857. }
  858. }
  859. func TestFeedIcon(t *testing.T) {
  860. expected := &FeedIcon{
  861. ID: 1,
  862. MimeType: "text/plain",
  863. Data: "data",
  864. }
  865. client := NewClientWithOptions(
  866. "http://mf",
  867. WithHTTPClient(
  868. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  869. expectRequest(t, http.MethodGet, "http://mf/v1/feeds/1/icon", nil, req)
  870. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  871. })))
  872. res, err := client.FeedIconContext(t.Context(), 1)
  873. if err != nil {
  874. t.Fatalf("Expected no error, got %v", err)
  875. }
  876. if !reflect.DeepEqual(res, expected) {
  877. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  878. }
  879. }
  880. func TestFeedEntry(t *testing.T) {
  881. expected := &Entry{
  882. ID: 1,
  883. Title: "Example",
  884. }
  885. client := NewClientWithOptions(
  886. "http://mf",
  887. WithHTTPClient(
  888. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  889. expectRequest(t, http.MethodGet, "http://mf/v1/feeds/1/entries/1", nil, req)
  890. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  891. })))
  892. res, err := client.FeedEntryContext(t.Context(), 1, 1)
  893. if err != nil {
  894. t.Fatalf("Expected no error, got %v", err)
  895. }
  896. if !reflect.DeepEqual(res, expected) {
  897. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  898. }
  899. }
  900. func TestCategoryEntry(t *testing.T) {
  901. expected := &Entry{
  902. ID: 1,
  903. Title: "Example",
  904. }
  905. client := NewClientWithOptions(
  906. "http://mf",
  907. WithHTTPClient(
  908. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  909. expectRequest(t, http.MethodGet, "http://mf/v1/categories/1/entries/1", nil, req)
  910. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  911. })))
  912. res, err := client.CategoryEntryContext(t.Context(), 1, 1)
  913. if err != nil {
  914. t.Fatalf("Expected no error, got %v", err)
  915. }
  916. if !reflect.DeepEqual(res, expected) {
  917. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  918. }
  919. }
  920. func TestEntry(t *testing.T) {
  921. expected := &Entry{
  922. ID: 1,
  923. Title: "Example",
  924. }
  925. client := NewClientWithOptions(
  926. "http://mf",
  927. WithHTTPClient(
  928. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  929. expectRequest(t, http.MethodGet, "http://mf/v1/entries/1", nil, req)
  930. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  931. })))
  932. res, err := client.EntryContext(t.Context(), 1)
  933. if err != nil {
  934. t.Fatalf("Expected no error, got %v", err)
  935. }
  936. if !reflect.DeepEqual(res, expected) {
  937. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  938. }
  939. }
  940. func TestEntries(t *testing.T) {
  941. expected := &EntryResultSet{
  942. Total: 1,
  943. Entries: Entries{
  944. {
  945. ID: 1,
  946. Title: "Example",
  947. },
  948. },
  949. }
  950. client := NewClientWithOptions(
  951. "http://mf",
  952. WithHTTPClient(
  953. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  954. expectRequest(t, http.MethodGet, "http://mf/v1/entries", nil, req)
  955. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  956. })))
  957. res, err := client.EntriesContext(t.Context(), nil)
  958. if err != nil {
  959. t.Fatalf("Expected no error, got %v", err)
  960. }
  961. if !reflect.DeepEqual(res, expected) {
  962. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  963. }
  964. }
  965. func TestFeedEntries(t *testing.T) {
  966. expected := &EntryResultSet{
  967. Total: 1,
  968. Entries: Entries{
  969. {
  970. ID: 1,
  971. Title: "Example",
  972. },
  973. },
  974. }
  975. client := NewClientWithOptions(
  976. "http://mf",
  977. WithHTTPClient(
  978. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  979. expectRequest(t, http.MethodGet, "http://mf/v1/feeds/1/entries?limit=10&offset=0", nil, req)
  980. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  981. })))
  982. res, err := client.FeedEntriesContext(t.Context(), 1, &Filter{
  983. Limit: 10,
  984. })
  985. if err != nil {
  986. t.Fatalf("Expected no error, got %v", err)
  987. }
  988. if !reflect.DeepEqual(res, expected) {
  989. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  990. }
  991. }
  992. func TestCategoryEntries(t *testing.T) {
  993. expected := &EntryResultSet{
  994. Total: 1,
  995. Entries: Entries{
  996. {
  997. ID: 1,
  998. Title: "Example",
  999. },
  1000. },
  1001. }
  1002. client := NewClientWithOptions(
  1003. "http://mf",
  1004. WithHTTPClient(
  1005. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1006. expectRequest(t, http.MethodGet, "http://mf/v1/categories/1/entries?limit=10&offset=0", nil, req)
  1007. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  1008. })))
  1009. res, err := client.CategoryEntriesContext(t.Context(), 1, &Filter{
  1010. Limit: 10,
  1011. })
  1012. if err != nil {
  1013. t.Fatalf("Expected no error, got %v", err)
  1014. }
  1015. if !reflect.DeepEqual(res, expected) {
  1016. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  1017. }
  1018. }
  1019. func TestUpdateEntries(t *testing.T) {
  1020. client := NewClientWithOptions(
  1021. "http://mf",
  1022. WithHTTPClient(
  1023. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1024. expectRequest(t, http.MethodPut, "http://mf/v1/entries", nil, req)
  1025. expectFromJSON(t, req.Body, &struct {
  1026. EntryIDs []int64 `json:"entry_ids"`
  1027. Status string `json:"status"`
  1028. }{
  1029. EntryIDs: []int64{1, 2},
  1030. Status: "read",
  1031. })
  1032. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  1033. })))
  1034. if err := client.UpdateEntriesContext(t.Context(), []int64{1, 2}, "read"); err != nil {
  1035. t.Fatalf("Expected no error, got %v", err)
  1036. }
  1037. }
  1038. func TestUpdateEntry(t *testing.T) {
  1039. expected := &Entry{
  1040. ID: 1,
  1041. Title: "Example",
  1042. }
  1043. client := NewClientWithOptions(
  1044. "http://mf",
  1045. WithHTTPClient(
  1046. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1047. expectRequest(t, http.MethodPut, "http://mf/v1/entries/1", nil, req)
  1048. expectFromJSON(t, req.Body, &EntryModificationRequest{
  1049. Title: &expected.Title,
  1050. })
  1051. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  1052. })))
  1053. res, err := client.UpdateEntryContext(t.Context(), 1, &EntryModificationRequest{
  1054. Title: &expected.Title,
  1055. })
  1056. if err != nil {
  1057. t.Fatalf("Expected no error, got %v", err)
  1058. }
  1059. if !reflect.DeepEqual(res, expected) {
  1060. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  1061. }
  1062. }
  1063. func TestToggleStarred(t *testing.T) {
  1064. client := NewClientWithOptions(
  1065. "http://mf",
  1066. WithHTTPClient(
  1067. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1068. expectRequest(t, http.MethodPut, "http://mf/v1/entries/1/star", nil, req)
  1069. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  1070. })))
  1071. if err := client.ToggleStarredContext(t.Context(), 1); err != nil {
  1072. t.Fatalf("Expected no error, got %v", err)
  1073. }
  1074. }
  1075. func TestSaveEntry(t *testing.T) {
  1076. client := NewClientWithOptions(
  1077. "http://mf",
  1078. WithHTTPClient(
  1079. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1080. expectRequest(t, http.MethodPost, "http://mf/v1/entries/1/save", nil, req)
  1081. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  1082. })))
  1083. if err := client.SaveEntryContext(t.Context(), 1); err != nil {
  1084. t.Fatalf("Expected no error, got %v", err)
  1085. }
  1086. }
  1087. func TestFetchEntryOriginalContent(t *testing.T) {
  1088. expected := "Example"
  1089. client := NewClientWithOptions(
  1090. "http://mf",
  1091. WithHTTPClient(
  1092. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1093. expectRequest(t, http.MethodGet, "http://mf/v1/entries/1/fetch-content", nil, req)
  1094. return jsonResponseFrom(t, http.StatusOK, http.Header{}, struct {
  1095. Content string `json:"content"`
  1096. }{
  1097. Content: expected,
  1098. })
  1099. })))
  1100. res, err := client.FetchEntryOriginalContentContext(t.Context(), 1)
  1101. if err != nil {
  1102. t.Fatalf("Expected no error, got %v", err)
  1103. }
  1104. if res != expected {
  1105. t.Fatalf("Expected %s, got %s", expected, res)
  1106. }
  1107. }
  1108. func TestFetchCounters(t *testing.T) {
  1109. expected := &FeedCounters{
  1110. ReadCounters: map[int64]int{
  1111. 2: 1,
  1112. },
  1113. UnreadCounters: map[int64]int{
  1114. 3: 1,
  1115. },
  1116. }
  1117. client := NewClientWithOptions(
  1118. "http://mf",
  1119. WithHTTPClient(
  1120. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1121. expectRequest(t, http.MethodGet, "http://mf/v1/feeds/counters", nil, req)
  1122. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  1123. })))
  1124. res, err := client.FetchCountersContext(t.Context())
  1125. if err != nil {
  1126. t.Fatalf("Expected no error, got %v", err)
  1127. }
  1128. if !reflect.DeepEqual(res, expected) {
  1129. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  1130. }
  1131. }
  1132. func TestFlushHistory(t *testing.T) {
  1133. client := NewClientWithOptions(
  1134. "http://mf",
  1135. WithHTTPClient(
  1136. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1137. expectRequest(t, http.MethodPut, "http://mf/v1/flush-history", nil, req)
  1138. return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
  1139. })))
  1140. if err := client.FlushHistoryContext(t.Context()); err != nil {
  1141. t.Fatalf("Expected no error, got %v", err)
  1142. }
  1143. }
  1144. func TestIcon(t *testing.T) {
  1145. expected := &FeedIcon{
  1146. ID: 1,
  1147. MimeType: "text/plain",
  1148. Data: "data",
  1149. }
  1150. client := NewClientWithOptions(
  1151. "http://mf",
  1152. WithHTTPClient(
  1153. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1154. expectRequest(t, http.MethodGet, "http://mf/v1/icons/1", nil, req)
  1155. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  1156. })))
  1157. res, err := client.IconContext(t.Context(), 1)
  1158. if err != nil {
  1159. t.Fatalf("Expected no error, got %v", err)
  1160. }
  1161. if !reflect.DeepEqual(res, expected) {
  1162. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  1163. }
  1164. }
  1165. func TestEnclosure(t *testing.T) {
  1166. expected := &Enclosure{
  1167. ID: 1,
  1168. URL: "http://example.com",
  1169. MimeType: "text/plain",
  1170. }
  1171. client := NewClientWithOptions(
  1172. "http://mf",
  1173. WithHTTPClient(
  1174. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1175. expectRequest(t, http.MethodGet, "http://mf/v1/enclosures/1", nil, req)
  1176. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  1177. })))
  1178. res, err := client.EnclosureContext(t.Context(), 1)
  1179. if err != nil {
  1180. t.Fatalf("Expected no error, got %v", err)
  1181. }
  1182. if !reflect.DeepEqual(res, expected) {
  1183. t.Fatalf("Expected %s, got %s", asJSON(expected), asJSON(res))
  1184. }
  1185. }
  1186. func TestUpdateEnclosure(t *testing.T) {
  1187. expected := &Enclosure{
  1188. ID: 1,
  1189. URL: "http://example.com",
  1190. MimeType: "text/plain",
  1191. }
  1192. client := NewClientWithOptions(
  1193. "http://mf",
  1194. WithHTTPClient(
  1195. newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
  1196. expectRequest(t, http.MethodPut, "http://mf/v1/enclosures/1", nil, req)
  1197. expectFromJSON(t, req.Body, &EnclosureUpdateRequest{
  1198. MediaProgression: 10,
  1199. })
  1200. return jsonResponseFrom(t, http.StatusOK, http.Header{}, expected)
  1201. })))
  1202. if err := client.UpdateEnclosureContext(t.Context(), 1, &EnclosureUpdateRequest{
  1203. MediaProgression: 10,
  1204. }); err != nil {
  1205. t.Fatalf("Expected no error, got %v", err)
  1206. }
  1207. }