diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-08-29 18:58:06 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-08-29 18:58:06 +0900 |
| commit | c2d900ec74e03e9c782cfe7b7ce06ff62cda6601 (patch) | |
| tree | fb13320bfdc62d810aa59769e8809dc2f707919e /pkg/net_test.go | |
| parent | bd4f29909e0750a4660eaf48e3169777a265b0ab (diff) | |
Closes #43.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'pkg/net_test.go')
| -rw-r--r-- | pkg/net_test.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/pkg/net_test.go b/pkg/net_test.go new file mode 100644 index 00000000..b16a2019 --- /dev/null +++ b/pkg/net_test.go @@ -0,0 +1,168 @@ +package pkg_test + +import ( + "crypto/sha512" + "io" + "io/fs" + "net/http" + "reflect" + "testing" + "testing/fstest" + "unique" + + "hakurei.app/check" + "hakurei.app/pkg" +) + +func TestHTTPGet(t *testing.T) { + t.Parallel() + + const testdata = "\x7f\xe1\x69\xa2\xdd\x63\x96\x26\x83\x79\x61\x8b\xf0\x3f\xd5\x16\x9a\x39\x3a\xdb\xcf\xb1\xbc\x8d\x33\xff\x75\xee\x62\x56\xa9\xf0\x27\xac\x13\x94\x69" + + testdataChecksum := func() unique.Handle[pkg.Checksum] { + h := sha512.New384() + h.Write([]byte(testdata)) + return unique.Make(pkg.Checksum(h.Sum(nil))) + }() + + var transport http.Transport + client := http.Client{Transport: &transport} + transport.RegisterProtocol("file", http.NewFileTransportFS(fstest.MapFS{ + "testdata": {Data: []byte(testdata), Mode: 0400}, + })) + + checkWithCache(t, []cacheTestCase{ + {"direct", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { + r := newRContext(t, c) + f := pkg.NewHTTPGet( + &client, + "file:///testdata", + testdataChecksum.Value(), + ) + var got []byte + if rc, err := f.Cure(r); err != nil { + t.Fatalf("Cure: error = %v", err) + } else if got, err = io.ReadAll(rc); err != nil { + t.Fatalf("ReadAll: error = %v", err) + } else if string(got) != testdata { + t.Fatalf("Cure: %x, want %x", got, testdata) + } else if err = rc.Close(); err != nil { + t.Fatalf("Close: error = %v", err) + } + + // check direct validation + f = pkg.NewHTTPGet( + &client, + "file:///testdata", + pkg.Checksum{}, + ) + wantErrMismatch := &pkg.ChecksumMismatchError{ + Got: testdataChecksum.Value(), + } + if rc, err := f.Cure(r); err != nil { + t.Fatalf("Cure: error = %v", err) + } else if got, err = io.ReadAll(rc); err != nil { + t.Fatalf("ReadAll: error = %v", err) + } else if string(got) != testdata { + t.Fatalf("Cure: %x, want %x", got, testdata) + } else if err = rc.Close(); !reflect.DeepEqual(err, wantErrMismatch) { + t.Fatalf("Close: error = %#v, want %#v", err, wantErrMismatch) + } + + // check fallback validation + if rc, err := f.Cure(r); err != nil { + t.Fatalf("Cure: error = %v", err) + } else if err = rc.Close(); !reflect.DeepEqual(err, wantErrMismatch) { + t.Fatalf("Close: error = %#v, want %#v", err, wantErrMismatch) + } + + // check direct response error + f = pkg.NewHTTPGet( + &client, + "file:///nonexistent", + pkg.Checksum{}, + ) + wantErrNotFound := pkg.ResponseStatusError(http.StatusNotFound) + if _, err := f.Cure(r); !reflect.DeepEqual(err, wantErrNotFound) { + t.Fatalf("Cure: error = %#v, want %#v", err, wantErrNotFound) + } + }, expectsFS{ + ".": {Mode: fs.ModeDir | 0700}, + "checksum": {Mode: fs.ModeDir | 0700}, + "identifier": {Mode: fs.ModeDir | 0700}, + "substitute": {Mode: fs.ModeDir | 0700}, + "work": {Mode: fs.ModeDir | 0700}, + }}, + + {"cure", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { + r := newRContext(t, c) + + f := pkg.NewHTTPGet( + &client, + "file:///testdata", + testdataChecksum.Value(), + ) + wantPathname := base.Append( + "identifier", + "COBRUwkxpIvZWJggpRxn7HVXiw6epXZOex8jGRJKpowpwukV7GRBY_LBvOJNQHue", + ) + if pathname, checksum, err := c.Cure(f); err != nil { + t.Fatalf("Cure: error = %v", err) + } else if !pathname.Is(wantPathname) { + t.Fatalf("Cure: %q, want %q", pathname, wantPathname) + } else if checksum != testdataChecksum { + t.Fatalf("Cure: %x, want %x", checksum.Value(), testdataChecksum.Value()) + } + + var got []byte + if rc, err := f.Cure(r); err != nil { + t.Fatalf("Cure: error = %v", err) + } else if got, err = io.ReadAll(rc); err != nil { + t.Fatalf("ReadAll: error = %v", err) + } else if string(got) != testdata { + t.Fatalf("Cure: %x, want %x", got, testdata) + } else if err = rc.Close(); err != nil { + t.Fatalf("Close: error = %v", err) + } + + // check load from cache + f = pkg.NewHTTPGet( + &client, + "file:///testdata", + testdataChecksum.Value(), + ) + if rc, err := f.Cure(r); err != nil { + t.Fatalf("Cure: error = %v", err) + } else if got, err = io.ReadAll(rc); err != nil { + t.Fatalf("ReadAll: error = %v", err) + } else if string(got) != testdata { + t.Fatalf("Cure: %x, want %x", got, testdata) + } else if err = rc.Close(); err != nil { + t.Fatalf("Close: error = %v", err) + } + + // check error passthrough + f = pkg.NewHTTPGet( + &client, + "file:///nonexistent", + pkg.Checksum{}, + ) + wantErrNotFound := pkg.ResponseStatusError(http.StatusNotFound) + if _, _, err := c.Cure(f); !reflect.DeepEqual(err, wantErrNotFound) { + t.Fatalf("Pathname: error = %#v, want %#v", err, wantErrNotFound) + } + }, expectsFS{ + ".": {Mode: fs.ModeDir | 0700}, + + "checksum": {Mode: fs.ModeDir | 0700}, + "checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU": {Mode: 0400, Data: []byte("\x7f\xe1\x69\xa2\xdd\x63\x96\x26\x83\x79\x61\x8b\xf0\x3f\xd5\x16\x9a\x39\x3a\xdb\xcf\xb1\xbc\x8d\x33\xff\x75\xee\x62\x56\xa9\xf0\x27\xac\x13\x94\x69")}, + + "identifier": {Mode: fs.ModeDir | 0700}, + "identifier/COBRUwkxpIvZWJggpRxn7HVXiw6epXZOex8jGRJKpowpwukV7GRBY_LBvOJNQHue": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU")}, + + "substitute": {Mode: fs.ModeDir | 0700}, + + "work": {Mode: fs.ModeDir | 0700}, + }}, + }) +} |
