Drop atime from the format spec and pin the file entry fields (closes #158)
check / check (push) Failing after 2m22s
check / check (push) Failing after 2m22s
atime left mf.proto earlier and nothing reads or writes it, but docs/FORMAT.md still narrated its removal and listed it among the determinism rules. The spec now describes the file entry by its fields only. A new test compares the MFFilePath message descriptor, by name and number, with a list copied from the spec's field table. It does not read the spec, so changing a field means changing the proto, the spec and that list together. Model: opus-5-5
This commit is contained in:
@@ -78,9 +78,6 @@ Each file entry contains:
|
|||||||
| `mtime` | 302 | Timestamp (optional) | Modification time |
|
| `mtime` | 302 | Timestamp (optional) | Modification time |
|
||||||
| `ctime` | 303 | Timestamp (optional) | Change time (inode metadata change) |
|
| `ctime` | 303 | Timestamp (optional) | Change time (inode metadata change) |
|
||||||
|
|
||||||
Field 304 (`atime`) has been removed from the specification. Access time is
|
|
||||||
volatile and non-deterministic; it is not useful for integrity verification.
|
|
||||||
|
|
||||||
## Path Rules
|
## Path Rules
|
||||||
|
|
||||||
All `path` values must satisfy these invariants:
|
All `path` values must satisfy these invariants:
|
||||||
@@ -130,7 +127,6 @@ By default, manifests are generated deterministically:
|
|||||||
|
|
||||||
- File entries are sorted by `path` in **lexicographic byte order**
|
- File entries are sorted by `path` in **lexicographic byte order**
|
||||||
- `createdAt` is omitted unless explicitly requested
|
- `createdAt` is omitted unless explicitly requested
|
||||||
- `atime` is never included (field removed from schema)
|
|
||||||
|
|
||||||
This ensures that two independent runs over the same directory tree produce
|
This ensures that two independent runs over the same directory tree produce
|
||||||
byte-identical `.mf` files (assuming file contents and metadata have not
|
byte-identical `.mf` files (assuming file contents and metadata have not
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
"sneak.berlin/go/mfer/mfer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// mf.pb.go is generated from mf.proto and committed. `make generate`
|
// mf.pb.go is generated from mf.proto and committed. `make generate`
|
||||||
@@ -27,3 +29,26 @@ func TestGeneratedCodeMatchesProto(t *testing.T) {
|
|||||||
"mfer/mf.proto has changed since mfer/mf.pb.go was generated "+
|
"mfer/mf.proto has changed since mfer/mf.pb.go was generated "+
|
||||||
"from it: run `make generate` and commit the result")
|
"from it: run `make generate` and commit the result")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A file entry has exactly the fields docs/FORMAT.md lists for MFFilePath.
|
||||||
|
func TestFileEntryFieldsMatchSpec(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
want := map[string]protoreflect.FieldNumber{
|
||||||
|
"path": 1,
|
||||||
|
"size": 2,
|
||||||
|
"hashes": 3,
|
||||||
|
"mimeType": 301,
|
||||||
|
"mtime": 302,
|
||||||
|
"ctime": 303,
|
||||||
|
}
|
||||||
|
|
||||||
|
got := map[string]protoreflect.FieldNumber{}
|
||||||
|
|
||||||
|
fields := (&mfer.MFFilePath{}).ProtoReflect().Descriptor().Fields()
|
||||||
|
for i := range fields.Len() {
|
||||||
|
got[string(fields.Get(i).Name())] = fields.Get(i).Number()
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, want, got)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user