@@ -646,13 +646,59 @@ func TestHandlerPushRejectsNormalizedEmptyProject(t *testing.T) {
646646 }
647647}
648648
649- func TestHandlerPushRejectsChunkIDPayloadMismatch (t * testing.T ) {
650- srv := New (& fakeStore {}, fakeAuth {}, 0 )
651- body := bytes .NewBufferString (`{"chunk_id":"deadbeef","project":"proj-a","created_by":"tester","data":{"sessions":[{"id":"s-1"}]}}` )
652- rec := httptest .NewRecorder ()
653- srv .Handler ().ServeHTTP (rec , httptest .NewRequest (http .MethodPost , "/sync/push" , body ))
654- if rec .Code != http .StatusBadRequest {
655- t .Fatalf ("expected 400, got %d body=%q" , rec .Code , rec .Body .String ())
649+ func TestHandlerPushUsesServerHashWhenClientChunkIDMissingOrMismatched (t * testing.T ) {
650+ payload := []byte (`{"sessions":[{"id":"s-1","directory":"/tmp/s-1"}]}` )
651+ normalizedPayload , err := coerceChunkProject (payload , "proj-a" )
652+ if err != nil {
653+ t .Fatalf ("coerce payload: %v" , err )
654+ }
655+ wantChunkID := chunkIDFromPayload (normalizedPayload )
656+ tests := []struct {
657+ name string
658+ requestChunkID string
659+ forbiddenStored string
660+ }{
661+ {name : "mismatched chunk id" , requestChunkID : "deadbeef" , forbiddenStored : "deadbeef" },
662+ {name : "empty chunk id" , requestChunkID : "" , forbiddenStored : "" },
663+ }
664+
665+ for _ , tt := range tests {
666+ t .Run (tt .name , func (t * testing.T ) {
667+ st := & fakeStore {}
668+ srv := New (st , fakeAuth {}, 0 )
669+ body := bytes .NewBufferString (`{"chunk_id":"` + tt .requestChunkID + `","project":"proj-a","created_by":"tester","data":` + string (payload ) + `}` )
670+
671+ rec := httptest .NewRecorder ()
672+ srv .Handler ().ServeHTTP (rec , httptest .NewRequest (http .MethodPost , "/sync/push" , body ))
673+ if rec .Code != http .StatusOK {
674+ t .Fatalf ("expected 200, got %d body=%q" , rec .Code , rec .Body .String ())
675+ }
676+ var response struct {
677+ ChunkID string `json:"chunk_id"`
678+ }
679+ if err := json .Unmarshal (rec .Body .Bytes (), & response ); err != nil {
680+ t .Fatalf ("decode response: %v" , err )
681+ }
682+ if response .ChunkID != wantChunkID {
683+ t .Fatalf ("expected response chunk_id %q, got %q" , wantChunkID , response .ChunkID )
684+ }
685+ if _ , ok := st .chunks [wantChunkID ]; ! ok {
686+ t .Fatalf ("expected store write under server chunk_id %q" , wantChunkID )
687+ }
688+ for storedChunkID := range st .chunks {
689+ if storedChunkID == "" {
690+ t .Fatalf ("expected stored chunk_id to be non-empty" )
691+ }
692+ if storedChunkID != wantChunkID {
693+ t .Fatalf ("expected stored chunk_id %q, got %q" , wantChunkID , storedChunkID )
694+ }
695+ }
696+ if tt .forbiddenStored != "" {
697+ if _ , ok := st .chunks [tt .forbiddenStored ]; ok {
698+ t .Fatalf ("expected client chunk_id %q not to be used for storage" , tt .forbiddenStored )
699+ }
700+ }
701+ })
656702 }
657703}
658704
0 commit comments