jojo/tests/integration/repo_avatar_test.go
Bram Hagens 48d2af5561 fix: skip repo avatar upload when no file is selected (#11335)
Submitting the repo avatar form without selecting a file shows a raw Go error: `Avatar.Open: open : no such file or directory.`. The existing `nil` check does not prevent this from happening.

The user avatar handler already guards against this same problem with [`form.Avatar != nil && form.Avatar.Filename != ""`](e1cecbd276/routers/web/user/setting/profile.go (L141)), I've done the same for the repo avatar handler.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11335
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Bram Hagens <bram@bramh.me>
Co-committed-by: Bram Hagens <bram@bramh.me>
2026-03-07 20:53:23 +01:00

94 lines
2.8 KiB
Go

// Copyright 2026 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
package integration
import (
"bytes"
"image/png"
"io"
"mime/multipart"
"net/http"
"testing"
repo_model "forgejo.org/models/repo"
"forgejo.org/models/unittest"
user_model "forgejo.org/models/user"
"forgejo.org/modules/avatar"
app_context "forgejo.org/services/context"
"forgejo.org/tests"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRepoAvatar(t *testing.T) {
defer tests.PrepareTestEnv(t)()
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user2.Name)
avatarURL := "/" + repo.OwnerName + "/" + repo.Name + "/settings/avatar"
t.Run("valid avatar", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
img, err := avatar.RandomImage([]byte("seed"))
require.NoError(t, err)
imgData := &bytes.Buffer{}
require.NoError(t, png.Encode(imgData, img))
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
require.NoError(t, writer.WriteField("source", "local"))
part, err := writer.CreateFormFile("avatar", "avatar.png")
require.NoError(t, err)
_, err = io.Copy(part, imgData)
require.NoError(t, err)
require.NoError(t, writer.Close())
req := NewRequestWithBody(t, "POST", avatarURL, body)
req.Header.Add("Content-Type", writer.FormDataContentType())
session.MakeRequest(t, req, http.StatusSeeOther)
flashCookie := session.GetCookie(app_context.CookieNameFlash)
require.NotNil(t, flashCookie)
assert.Contains(t, flashCookie.Value, "success")
// Verify avatar was actually set
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
assert.NotEmpty(t, repo.CustomAvatarRelativePath())
// Verify avatar is accessible
req = NewRequest(t, "GET", "/repo-avatars/"+repo.Avatar)
_ = session.MakeRequest(t, req, http.StatusOK)
// Clean up
req = NewRequest(t, "POST", avatarURL+"/delete")
session.MakeRequest(t, req, http.StatusOK)
})
t.Run("no file selected", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
// Simulate what a browser sends when user did not select a file
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
require.NoError(t, writer.WriteField("source", "local"))
_, err := writer.CreateFormFile("avatar", "")
require.NoError(t, err)
require.NoError(t, writer.Close())
req := NewRequestWithBody(t, "POST", avatarURL, body)
req.Header.Add("Content-Type", writer.FormDataContentType())
session.MakeRequest(t, req, http.StatusSeeOther)
// Should silently skip
flashCookie := session.GetCookie(app_context.CookieNameFlash)
if flashCookie != nil {
assert.NotContains(t, flashCookie.Value, "error")
}
})
}