package api

import (
	"context"
	"errors"
	"io"
	"net/http"
	"net/http/httptest"
	"syscall"
	"testing"
)

func TestExpectedClientDisconnect(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "/v1/images/1/primary", nil)
	for _, err := range []error{
		context.Canceled,
		syscall.EPIPE,
		syscall.ECONNRESET,
		errors.New("write tcp: broken pipe"),
		errors.New("client disconnected"),
	} {
		if !expectedClientDisconnect(req, err) {
			t.Errorf("%q should be an expected client disconnect", err)
		}
	}
	if expectedClientDisconnect(req, io.ErrUnexpectedEOF) {
		t.Fatal("an upstream truncated image must remain a real warning")
	}
}

func TestExpectedClientDisconnectUsesRequestContext(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	cancel()
	req := httptest.NewRequest(http.MethodGet, "/v1/images/1/primary", nil).WithContext(ctx)
	if !expectedClientDisconnect(req, errors.New("opaque response writer error")) {
		t.Fatal("a cancelled request should be treated as viewer cancellation")
	}
}

func TestTaggedImageConditionalRequestSkipsUpstream(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "/v1/images/1/primary?tag=abc123", nil)
	req.Header.Set("If-None-Match", `"abc123"`)
	rec := httptest.NewRecorder()

	if !writeNotModifiedForTag(rec, req, "abc123") {
		t.Fatal("matching image tag should short-circuit")
	}
	if rec.Code != http.StatusNotModified {
		t.Fatalf("status = %d, want 304", rec.Code)
	}
	if got := rec.Header().Get("ETag"); got != `"abc123"` {
		t.Fatalf("etag = %q", got)
	}
}
