···11# Contributing to Chunk
2233-You might need to [install Staticcheck](https://staticcheck.io/docs/getting-started/#installation) if you don't have it in your system yet.
33+You might need to [install golangci-lint](https://golangci-lint.run) if you don't have it in your system yet.
4455Then, write and run tests, and use the auto-format as well as the linter tools:
6677```console
88$ gofmt -w ./
99-$ staticcheck ./...
99+$ golangci-lint run ./...
1010$ go test -race ./...
1111```
+20-5
downloader.go
···44 "bytes"
55 "context"
66 "fmt"
77+ "log/slog"
78 "net/http"
89 "net/url"
910 "os"
···126127 if err != nil {
127128 return nil, fmt.Errorf("error sending a get http request to %s: %w", u, err)
128129 }
129129- defer resp.Body.Close()
130130+ defer func() {
131131+ if err := resp.Body.Close(); err != nil {
132132+ slog.Warn("error closing HTTP response body", "url", u, "chunk", c.rangeHeader(), "error", err)
133133+ }
134134+ }()
130135 if resp.StatusCode != http.StatusPartialContent && resp.StatusCode != http.StatusOK {
131136 return nil, fmt.Errorf("got http response %s from %s", resp.Status, u)
132137 }
···193198 return 0, fmt.Errorf("error sending get http request to %s: %w", u, err)
194199 }
195200 resp := <-ch
196196- defer resp.Body.Close()
201201+ defer func() {
202202+ if err := resp.Body.Close(); err != nil {
203203+ slog.Warn("error closing HTTP response body", "url", u, "error", err)
204204+ }
205205+ }()
197206 if resp.ContentLength <= 0 {
198207 var s int64
199208 r := strings.TrimSpace(resp.Header.Get("Content-Range"))
···201210 return 0, fmt.Errorf("could not get content length for %s", u)
202211 }
203212 p := strings.Split(r, "/")
204204- fmt.Sscan(p[len(p)-1], &s)
213213+ if _, err := fmt.Sscan(p[len(p)-1], &s); err != nil {
214214+ return 0, fmt.Errorf("error parsing content range for %s: %w", u, err)
215215+ }
205216 return s, nil
206217 }
207218 return resp.ContentLength, nil
···278289 var urlDownload sync.WaitGroup
279290 defer func() {
280291 urlDownload.Wait()
281281- p.close()
282282- f.Close()
292292+ if err := p.close(); err != nil {
293293+ slog.Warn("error closing progress file", "url", s.URL, "path", s.DownloadedFilePath, "error", err)
294294+ }
295295+ if err := f.Close(); err != nil {
296296+ slog.Error("error closing downloaded file", "url", s.URL, "path", s.DownloadedFilePath, "error", err)
297297+ }
283298 }()
284299 if err := f.Truncate(int64(t)); err != nil {
285300 s.Error = fmt.Errorf("error truncating %s to %d: %w", path, t, err)
+53-13
downloader_test.go
···6868 w.Header().Add("Content-Length", "2")
6969 return
7070 }
7171- fmt.Fprint(w, "42")
7171+ if _, err := fmt.Fprint(w, "42"); err != nil {
7272+ t.Errorf("failed to write response: %v", err)
7373+ }
7274 },
7375 ))
7476 defer s.Close()
···7880 ch := d.Download(s.URL + "/My%20File.txt")
7981 <-ch // discard the first status (just the file size)
8082 got := <-ch
8181- defer os.Remove(got.DownloadedFilePath)
8383+ defer func() {
8484+ if err := os.Remove(got.DownloadedFilePath); err != nil {
8585+ t.Errorf("failed to remove test file: %v", err)
8686+ }
8787+ }()
82888389 if got.Error != nil {
8490 t.Errorf("invalid error. want:nil got:%q", got.Error)
···121127 if err != nil {
122128 t.Errorf("expected no error creating zip archive, got %s", err)
123129 }
124124- defer z.Close()
130130+ defer func() {
131131+ if err := z.Close(); err != nil {
132132+ t.Errorf("failed to close zip file: %v", err)
133133+ }
134134+ }()
125135 w := zip.NewWriter(z)
126136 f, err := w.Create("file.txt")
127137 if err != nil {
128138 t.Errorf("expected no error creating archived file, got %s", err)
129139 }
130130- defer w.Close()
140140+ defer func() {
141141+ if err := w.Close(); err != nil {
142142+ t.Errorf("failed to close zip writer: %v", err)
143143+ }
144144+ }()
131145 if _, err := f.Write(expected); err != nil {
132146 t.Errorf("expected no error writing to archived file, got %s", err)
133147 }
···143157144158 // download
145159 var got string
146146- defer os.Remove(got)
160160+ defer func() {
161161+ if got != "" {
162162+ if err := os.Remove(got); err != nil {
163163+ t.Errorf("failed to remove test file: %v", err)
164164+ }
165165+ }
166166+ }()
147167 d := DefaultDownloader()
148168 d.OutputDir = t.TempDir()
149169 for g := range d.Download(s.URL + "/archive.zip") {
···158178 if err != nil {
159179 t.Errorf("expected no error opening downloaded zip archive %s, got %s", got, err)
160180 }
161161- defer a.Close()
181181+ defer func() {
182182+ if err := a.Close(); err != nil {
183183+ t.Errorf("failed to close zip reader: %v", err)
184184+ }
185185+ }()
162186 r, err := a.Open("file.txt")
163187 if err != nil {
164188 t.Errorf("expected no error reading downloaded zip archive, got %s", err)
165189 }
166166- defer r.Close()
190190+ defer func() {
191191+ if err := r.Close(); err != nil {
192192+ t.Errorf("failed to close zip file reader: %v", err)
193193+ }
194194+ }()
167195 var b bytes.Buffer
168196 if _, err := io.Copy(&b, r); err != nil {
169197 t.Errorf("expected no error reading archived file, got %s", err)
···193221 if atomic.CompareAndSwapInt32(&attempts, 0, 1) {
194222 tc.proc(w)
195223 }
196196- fmt.Fprint(w, "42")
224224+ if _, err := fmt.Fprint(w, "42"); err != nil {
225225+ t.Errorf("failed to write response: %v", err)
226226+ }
197227 },
198228 ))
199229 defer s.Close()
···256286 url, first := func() (string, DownloadStatus) {
257287 s := httptest.NewServer(http.HandlerFunc(
258288 func(w http.ResponseWriter, r *http.Request) {
259259- fmt.Fprint(w, "42")
289289+ if _, err := fmt.Fprint(w, "42"); err != nil {
290290+ t.Errorf("failed to write response: %v", err)
291291+ }
260292 },
261293 ))
262294 defer s.Close()
···353385func TestGetDownloadSize_ContentLength(t *testing.T) {
354386 s := httptest.NewServer(http.HandlerFunc(
355387 func(w http.ResponseWriter, r *http.Request) {
356356- fmt.Fprint(w, "Test")
388388+ if _, err := fmt.Fprint(w, "Test"); err != nil {
389389+ t.Errorf("failed to write response: %v", err)
390390+ }
357391 },
358392 ))
359393 defer s.Close()
···377411 w.WriteHeader(http.StatusTooManyRequests)
378412 return
379413 }
380380- fmt.Fprint(w, "Test")
414414+ if _, err := fmt.Fprint(w, "Test"); err != nil {
415415+ t.Errorf("failed to write response: %v", err)
416416+ }
381417 },
382418 ))
383419 defer s.Close()
···397433 s := httptest.NewServer(http.HandlerFunc(
398434 func(w http.ResponseWriter, r *http.Request) {
399435 w.Header().Set("Content-Range", "bytes 1-10/123")
400400- fmt.Fprint(w, "")
436436+ if _, err := fmt.Fprint(w, ""); err != nil {
437437+ t.Errorf("failed to write response: %v", err)
438438+ }
401439 },
402440 ))
403441 defer s.Close()
···428466func TestGetDownloadSize_NoContent(t *testing.T) {
429467 s := httptest.NewServer(http.HandlerFunc(
430468 func(w http.ResponseWriter, r *http.Request) {
431431- fmt.Fprint(w, "")
469469+ if _, err := fmt.Fprint(w, ""); err != nil {
470470+ t.Errorf("failed to write response: %v", err)
471471+ }
432472 },
433473 ))
434474 defer s.Close()