mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-19 07:40:20 +00:00
fcb9bd7bd6
- Add unit tests for API endpoints (db, error, files, gpg, graph, metrics, publish, repos, snapshot, storage, task) - Add command-line interface tests for all cmd subcommands - Add database tests including race condition tests for etcddb and goleveldb - Add package management tests (collections, contents, graph, import, index files, dependencies) - Add infrastructure tests (pgp, systemd activation, task management) - Add utility tests (checksum, config accessor, logging, sanitize) - Add race condition tests for concurrent operations Test coverage improves reliability and helps catch regressions early.
214 lines
6.9 KiB
Go
214 lines
6.9 KiB
Go
package api
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
. "gopkg.in/check.v1"
|
|
)
|
|
|
|
type GPGTestSuite struct {
|
|
router *gin.Engine
|
|
}
|
|
|
|
var _ = Suite(&GPGTestSuite{})
|
|
|
|
func (s *GPGTestSuite) SetUpTest(c *C) {
|
|
s.router = gin.New()
|
|
s.router.POST("/api/gpg/key", apiGPGAddKey)
|
|
|
|
gin.SetMode(gin.TestMode)
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeyStructure(c *C) {
|
|
// Test GPG key add endpoint structure with sample key data
|
|
keyData := `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
Version: GnuPG v1
|
|
|
|
mQINBFKuaIQBEAC+JC5od6Vw1tz2SEfBE7tBLQhNy3z2SIu7iNC3Bi/W6xUy5YKw
|
|
sample key data for testing
|
|
-----END PGP PUBLIC KEY BLOCK-----`
|
|
|
|
req, _ := http.NewRequest("POST", "/api/gpg/key", bytes.NewBufferString(keyData))
|
|
req.Header.Set("Content-Type", "application/pgp-keys")
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Will likely error due to no context or invalid key, but tests structure
|
|
c.Check(w.Code, Not(Equals), 200)
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeyEmptyBody(c *C) {
|
|
// Test GPG key add with empty body
|
|
req, _ := http.NewRequest("POST", "/api/gpg/key", bytes.NewBufferString(""))
|
|
req.Header.Set("Content-Type", "application/pgp-keys")
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Should handle empty body gracefully
|
|
c.Check(w.Code, Not(Equals), 200)
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeyInvalidData(c *C) {
|
|
// Test GPG key add with invalid key data
|
|
invalidKeys := []string{
|
|
"not a pgp key",
|
|
"-----BEGIN PGP PUBLIC KEY BLOCK-----\ninvalid\n-----END PGP PUBLIC KEY BLOCK-----",
|
|
"random text data",
|
|
"<xml>not a key</xml>",
|
|
"-----BEGIN CERTIFICATE-----\ninvalid cert\n-----END CERTIFICATE-----",
|
|
}
|
|
|
|
for _, keyData := range invalidKeys {
|
|
req, _ := http.NewRequest("POST", "/api/gpg/key", bytes.NewBufferString(keyData))
|
|
req.Header.Set("Content-Type", "application/pgp-keys")
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Should handle invalid key data gracefully without crashing
|
|
c.Check(w.Code, Not(Equals), 0, Commentf("Key data: %s", keyData[:min(len(keyData), 50)]))
|
|
}
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeyHTTPMethods(c *C) {
|
|
// Test that only POST method is allowed
|
|
deniedMethods := []string{"GET", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"}
|
|
|
|
for _, method := range deniedMethods {
|
|
req, _ := http.NewRequest(method, "/api/gpg/key", nil)
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
c.Check(w.Code, Equals, 404, Commentf("Method: %s should be denied", method))
|
|
}
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeyContentTypes(c *C) {
|
|
// Test different content types
|
|
contentTypes := []string{
|
|
"application/pgp-keys",
|
|
"text/plain",
|
|
"application/x-pgp-message",
|
|
"application/octet-stream",
|
|
"",
|
|
}
|
|
|
|
keyData := "-----BEGIN PGP PUBLIC KEY BLOCK-----\nsample\n-----END PGP PUBLIC KEY BLOCK-----"
|
|
|
|
for _, contentType := range contentTypes {
|
|
req, _ := http.NewRequest("POST", "/api/gpg/key", bytes.NewBufferString(keyData))
|
|
if contentType != "" {
|
|
req.Header.Set("Content-Type", contentType)
|
|
}
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Should handle different content types without crashing
|
|
c.Check(w.Code, Not(Equals), 0, Commentf("Content-Type: %s", contentType))
|
|
}
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeyLargePayload(c *C) {
|
|
// Test with large payload (simulate large key file)
|
|
largeKeyData := "-----BEGIN PGP PUBLIC KEY BLOCK-----\n"
|
|
for i := 0; i < 1000; i++ {
|
|
largeKeyData += "large key data line " + string(rune(i)) + "\n"
|
|
}
|
|
largeKeyData += "-----END PGP PUBLIC KEY BLOCK-----"
|
|
|
|
req, _ := http.NewRequest("POST", "/api/gpg/key", bytes.NewBufferString(largeKeyData))
|
|
req.Header.Set("Content-Type", "application/pgp-keys")
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Should handle large payloads without crashing
|
|
c.Check(w.Code, Not(Equals), 0)
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeyBinaryData(c *C) {
|
|
// Test with binary data
|
|
binaryData := []byte{0x00, 0x01, 0x02, 0x03, 0xFF, 0xFE, 0xFD}
|
|
|
|
req, _ := http.NewRequest("POST", "/api/gpg/key", bytes.NewBuffer(binaryData))
|
|
req.Header.Set("Content-Type", "application/octet-stream")
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Should handle binary data without crashing
|
|
c.Check(w.Code, Not(Equals), 0)
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeySpecialCharacters(c *C) {
|
|
// Test with special characters and encoding
|
|
specialKeys := []string{
|
|
"-----BEGIN PGP PUBLIC KEY BLOCK-----\nключ с русскими символами\n-----END PGP PUBLIC KEY BLOCK-----",
|
|
"-----BEGIN PGP PUBLIC KEY BLOCK-----\n中文字符测试\n-----END PGP PUBLIC KEY BLOCK-----",
|
|
"-----BEGIN PGP PUBLIC KEY BLOCK-----\n🔑 emoji key 🔐\n-----END PGP PUBLIC KEY BLOCK-----",
|
|
"-----BEGIN PGP PUBLIC KEY BLOCK-----\n\"quotes\" and 'apostrophes'\n-----END PGP PUBLIC KEY BLOCK-----",
|
|
"-----BEGIN PGP PUBLIC KEY BLOCK-----\n<>&\"'`\n-----END PGP PUBLIC KEY BLOCK-----",
|
|
}
|
|
|
|
for i, keyData := range specialKeys {
|
|
req, _ := http.NewRequest("POST", "/api/gpg/key", bytes.NewBufferString(keyData))
|
|
req.Header.Set("Content-Type", "application/pgp-keys; charset=utf-8")
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Should handle special characters without crashing
|
|
c.Check(w.Code, Not(Equals), 0, Commentf("Special key test #%d", i+1))
|
|
}
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeyErrorHandling(c *C) {
|
|
// Test various error conditions
|
|
errorTests := []struct {
|
|
description string
|
|
data string
|
|
contentType string
|
|
expectError bool
|
|
}{
|
|
{"Empty key", "", "application/pgp-keys", true},
|
|
{"Malformed header", "-----BEGIN WRONG BLOCK-----\ndata\n-----END WRONG BLOCK-----", "application/pgp-keys", true},
|
|
{"Missing end", "-----BEGIN PGP PUBLIC KEY BLOCK-----\ndata", "application/pgp-keys", true},
|
|
{"Missing begin", "data\n-----END PGP PUBLIC KEY BLOCK-----", "application/pgp-keys", true},
|
|
{"Only whitespace", " \n\t\r\n ", "application/pgp-keys", true},
|
|
{"JSON data", `{"key": "value"}`, "application/json", true},
|
|
{"XML data", `<key>value</key>`, "application/xml", true},
|
|
}
|
|
|
|
for _, test := range errorTests {
|
|
req, _ := http.NewRequest("POST", "/api/gpg/key", bytes.NewBufferString(test.data))
|
|
req.Header.Set("Content-Type", test.contentType)
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Should handle errors gracefully without crashing
|
|
c.Check(w.Code, Not(Equals), 0, Commentf("Test: %s", test.description))
|
|
}
|
|
}
|
|
|
|
func (s *GPGTestSuite) TestGPGAddKeyReliability(c *C) {
|
|
// Test multiple sequential calls for reliability
|
|
keyData := "-----BEGIN PGP PUBLIC KEY BLOCK-----\ntest key data\n-----END PGP PUBLIC KEY BLOCK-----"
|
|
|
|
for i := 0; i < 5; i++ {
|
|
req, _ := http.NewRequest("POST", "/api/gpg/key", bytes.NewBufferString(keyData))
|
|
req.Header.Set("Content-Type", "application/pgp-keys")
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Should be consistent across multiple calls
|
|
c.Check(w.Code, Not(Equals), 0, Commentf("Call #%d", i+1))
|
|
}
|
|
}
|
|
|
|
// Helper function for minimum of two integers
|
|
func min(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
} |