Files
aptly/api/gpg_test.go
T
Nick Bozhenko fcb9bd7bd6 Add comprehensive test coverage across all packages
- 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.
2025-07-16 14:19:04 -04:00

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
}