marky

Lightweight bookmarking + plaintext archive
Log | Files | Refs | README | LICENSE

update_archive_test.go (3263B)


      1 package internal
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/json"
      6 	"io"
      7 	"net/http"
      8 	"net/http/cookiejar"
      9 	"net/http/httptest"
     10 	"testing"
     11 )
     12 
     13 func TestUpdateURL_RefetchArchiveAndRejectOnError(t *testing.T) {
     14 	t.Parallel()
     15 
     16 	// HTML servers
     17 	good := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
     18 		if r.Method == http.MethodHead {
     19 			w.Header().Set("Content-Type", "text/html; charset=utf-8")
     20 			return
     21 		}
     22 		w.Header().Set("Content-Type", "text/html; charset=utf-8")
     23 		io.WriteString(w, "<!doctype html><html><head><title>T1</title></head><body>alpha</body></html>")
     24 	}))
     25 	defer good.Close()
     26 	changed := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
     27 		if r.Method == http.MethodHead {
     28 			w.Header().Set("Content-Type", "text/html; charset=utf-8")
     29 			return
     30 		}
     31 		w.Header().Set("Content-Type", "text/html; charset=utf-8")
     32 		io.WriteString(w, "<!doctype html><html><head><title>T2</title></head><body>bravo</body></html>")
     33 	}))
     34 	defer changed.Close()
     35 	failing := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
     36 		if r.Method == http.MethodHead {
     37 			w.Header().Set("Content-Type", "text/html; charset=utf-8")
     38 			return
     39 		}
     40 		http.Error(w, "nope", http.StatusNotFound)
     41 	}))
     42 	defer failing.Close()
     43 
     44 	db, _ := OpenAtPath(t.Context(), t.TempDir()+"/upd.db")
     45 	t.Cleanup(func() { _ = db.Close() })
     46 	h, _ := NewHandler(db)
     47 	srv := httptest.NewServer(h)
     48 	defer srv.Close()
     49 
     50 	jar, _ := cookiejar.New(nil)
     51 	client := &http.Client{Jar: jar}
     52 	// signup
     53 	b, _ := json.Marshal(map[string]string{"username": "upd", "password": "pw"})
     54 	r, _ := http.NewRequest(http.MethodPost, srv.URL+"/signup", bytes.NewReader(b))
     55 	r.Header.Set("Content-Type", "application/json")
     56 	rs, _ := client.Do(r)
     57 	if rs.StatusCode != 200 {
     58 		t.Fatalf("signup %d", rs.StatusCode)
     59 	}
     60 	rs.Body.Close()
     61 
     62 	// create initial
     63 	cr := postJSONWithClient[map[string]any](t, client, srv.URL+"/bookmarks", map[string]any{"url": good.URL}, 201)
     64 	id := int(cr["id"].(float64))
     65 
     66 	// update URL to changed (should refetch and succeed)
     67 	putJSONWithClient[map[string]any](t, client, srv.URL+"/bookmarks/"+itoa(id), map[string]any{"url": changed.URL, "title": "First"}, 200)
     68 	// archive should contain 'bravo'
     69 	resp := getWithClient(t, client, srv.URL+"/bookmarks/"+itoa(id)+"/archive", 200)
     70 	body, _ := io.ReadAll(resp.Body)
     71 	resp.Body.Close()
     72 	if !bytes.Contains(bytes.ToLower(body), []byte("bravo")) {
     73 		t.Fatalf("expected new archive to contain bravo, got %q", string(body))
     74 	}
     75 
     76 	// update URL to failing (fetch GET 404) should reject
     77 	req, _ := http.NewRequest(http.MethodPut, srv.URL+"/bookmarks/"+itoa(id), bytes.NewReader([]byte("{\"url\":\""+failing.URL+"\",\"title\":\"First\"}")))
     78 	req.Header.Set("Content-Type", "application/json")
     79 	rs2, _ := client.Do(req)
     80 	if rs2.StatusCode != http.StatusUnprocessableEntity {
     81 		t.Fatalf("expected 422 on fetch failure, got %d", rs2.StatusCode)
     82 	}
     83 	rs2.Body.Close()
     84 
     85 	// ensure URL not changed
     86 	list := getJSONWithClient[[]map[string]any](t, client, srv.URL+"/bookmarks", 200)
     87 	if len(list) != 1 {
     88 		t.Fatalf("expected 1 bookmark, got %d", len(list))
     89 	}
     90 	if list[0]["url"].(string) != changed.URL {
     91 		t.Fatalf("expected url to remain %q, got %q", changed.URL, list[0]["url"])
     92 	}
     93 }