Documentation
¶
Overview ¶
Package filetest is the conformance suite for contracts.Service, a Storage in memory that the suite runs against, and a fake Service that passes it.
It exists because an interface is justified by a passing fake and not by a second production implementation (AGENTS.md rule 8). RunService is the specification written as executable cases; the real service and the fake both run it.
Index ¶
- Constants
- func RunService(t *testing.T, h Harness)
- type Fake
- func (f *Fake) Delete(_ context.Context, _ db.Tx[db.Tenant], id uuid.UUID) (*contracts.File, error)
- func (f *Fake) Open(ctx context.Context, _ db.Tx[db.Tenant], id uuid.UUID, anonymous bool) (*contracts.File, io.ReadCloser, error)
- func (f *Fake) Published() []string
- func (f *Fake) Upload(ctx context.Context, open contracts.Tx, up contracts.Upload) (*contracts.File, error)
- type Fixture
- type Harness
- type Memory
Constants ¶
const Limit = 1 << 10
Limit is the largest upload the suite's implementations accept. It is small so that a case can go past it without allocating anything worth mentioning.
Variables ¶
This section is empty.
Functions ¶
func RunService ¶
RunService is the conformance suite. Every implementation of contracts.Service passes it, or it is not one.
Types ¶
type Fake ¶
type Fake struct {
// contains filtered or unexported fields
}
Fake is contracts.Service over a map of rows and whatever Storage it is given: the same rules, no database, no transaction. A consumer that wants to test what it does when a file is uploaded takes one of these and a Memory.
It ignores the transaction it is handed, and that is the honest limit of it: it cannot tell a caller that a write did not commit, because nothing here commits. What it does keep is the order the real service keeps — bytes first, row second, and the bytes removed again when the row is refused — because that order is the whole design and a fake that got it wrong would let a consumer test against a module that does not exist.
func (*Fake) Open ¶
func (f *Fake) Open(ctx context.Context, _ db.Tx[db.Tenant], id uuid.UUID, anonymous bool) (*contracts.File, io.ReadCloser, error)
Open mirrors internal.Service.Open.
func (*Fake) Upload ¶
func (f *Fake) Upload(ctx context.Context, open contracts.Tx, up contracts.Upload) (*contracts.File, error)
Upload mirrors internal.Service.Upload, including the order: the bytes are stored before the transaction is asked for, because a body arrives at the client's pace and nothing may be open while it does.
type Fixture ¶
type Fixture struct {
Ctx context.Context
Tx db.Tx[db.Tenant]
Service contracts.Service
// Storage is the same store the Service was built on, for the cases about
// what is left behind: an upload that was refused, and a delete that has
// not been handled yet.
Storage contracts.Storage
// Keys is every key the storage currently holds, which is the one question
// contracts.Storage does not answer and the only way to see an orphan.
Keys func() []string
// Published is the events the implementation has published, in order.
Published func() []string
}
Fixture is one case's world: a Service, the transaction its commands take, and the storage behind it, so a case can check that the bytes went where the row says they did.
type Memory ¶
type Memory struct {
// contains filtered or unexported fields
}
Memory is contracts.Storage over a map, for a consumer — and for the conformance suite — that wants a file module without a disk. It keeps the same promises the disk one does: a key that already exists is refused, a key with nothing at it is not an error to delete, and Get answers ErrNoBlob.