diff --git a/Makefile b/Makefile index 61cf7f9..8070935 100644 --- a/Makefile +++ b/Makefile @@ -3,25 +3,43 @@ SCRIPT_DIR = "scripts" .PHONY: format-and-lint run-unit-tests run-integration-tests \ spin-up-integration-test-docker-containers \ shut-down-integration-test-docker-containers \ - spin-up-docker-containers shut-down-docker-containers - + spin-up-docker-containers shut-down-docker-containers help + +# Help target to list all available targets +help: + @echo "Available Makefile targets:" + @echo " format-and-lint - Run the format and linting script" + @echo " run-unit-tests - Run the unit tests" + @echo " run-integration-tests - Run the integration tests" + @echo " spin-up-integration-test-docker-containers - Spin up Docker containers for integration tests (Postgres, Azure Blob Storage)" + @echo " shut-down-integration-test-docker-containers - Shut down Docker containers for integration tests" + @echo " spin-up-docker-containers - Spin up Docker containers with internal containerized applications" + @echo " shut-down-docker-containers - Shut down the application Docker containers" + +# Run the format and lint script format-and-lint: @cd $(SCRIPT_DIR) && ./format-and-lint.sh +# Run unit tests run-unit-tests: @cd $(SCRIPT_DIR) && ./run-test.sh -u +# Run integration tests run-integration-tests: @cd $(SCRIPT_DIR) && ./run-test.sh -i +# Spin up Docker containers for integration tests spin-up-integration-test-docker-containers: docker-compose up -d postgres azure-blob-storage +# Shut down Docker containers for integration tests shut-down-integration-test-docker-containers: docker-compose down postgres azure-blob-storage -v +# Spin up Docker containers with internal containerized applications spin-up-docker-containers: docker-compose up -d --build +# Shut down Docker containers with internal containerized applications shut-down-docker-containers: - docker-compose down -v \ No newline at end of file + docker-compose down -v diff --git a/cmd/crypto-vault-cli/internal/commands/aes-commands.go b/cmd/crypto-vault-cli/internal/commands/aes-commands.go index 1ac57a4..3d7af43 100644 --- a/cmd/crypto-vault-cli/internal/commands/aes-commands.go +++ b/cmd/crypto-vault-cli/internal/commands/aes-commands.go @@ -24,7 +24,7 @@ func EncryptAESCmd(cmd *cobra.Command, args []string) { log.Fatalf("Error: input, output, and keyDir flags are required\n") } - aes := &cryptography.AESCrypto{} + aes := &cryptography.AES{} // Generate AES Key key, err := aes.GenerateKey(keySize) @@ -85,7 +85,7 @@ func DecryptAESCmd(cmd *cobra.Command, args []string) { log.Fatalf("Error reading encrypted file: %v\n", err) } - aes := &cryptography.AESCrypto{} + aes := &cryptography.AES{} decryptedData, err := aes.Decrypt(encryptedData, key) if err != nil { diff --git a/cmd/crypto-vault-cli/internal/commands/ecdsa-commands.go b/cmd/crypto-vault-cli/internal/commands/ecdsa-commands.go index 9ee45e1..9199d6f 100644 --- a/cmd/crypto-vault-cli/internal/commands/ecdsa-commands.go +++ b/cmd/crypto-vault-cli/internal/commands/ecdsa-commands.go @@ -26,13 +26,13 @@ func SignECCCmd(cmd *cobra.Command, args []string) { } // ECC implementation - ECCrypto := &cryptography.ECCrypto{} + EC := &cryptography.EC{} var privateKey *ecdsa.PrivateKey var publicKey *ecdsa.PublicKey var err error // Generate new ECC keys if no private key is provided - privateKey, publicKey, err = ECCrypto.GenerateKeys(elliptic.P256()) + privateKey, publicKey, err = EC.GenerateKeys(elliptic.P256()) if err != nil { log.Fatalf("Error generating ECC keys: %v\n", err) } @@ -44,7 +44,7 @@ func SignECCCmd(cmd *cobra.Command, args []string) { } // Sign the file content (hash the content before signing) - signature, err := ECCrypto.Sign(fileContent, privateKey) + signature, err := EC.Sign(fileContent, privateKey) if err != nil { log.Fatalf("Error signing file content: %v\n", err) } @@ -57,7 +57,7 @@ func SignECCCmd(cmd *cobra.Command, args []string) { if privateKey != nil && keyDir != "" { privateKeyFilePath := fmt.Sprintf("%s/%s-private_key.pem", keyDir, uniqueID.String()) - err = ECCrypto.SavePrivateKeyToFile(privateKey, privateKeyFilePath) + err = EC.SavePrivateKeyToFile(privateKey, privateKeyFilePath) if err != nil { log.Fatalf("Error saving private key: %v\n", err) } @@ -66,7 +66,7 @@ func SignECCCmd(cmd *cobra.Command, args []string) { if publicKey != nil && keyDir != "" { publicKeyFilePath := fmt.Sprintf("%s/%s-public_key.pem", keyDir, uniqueID.String()) - err = ECCrypto.SavePublicKeyToFile(publicKey, publicKeyFilePath) + err = EC.SavePublicKeyToFile(publicKey, publicKeyFilePath) if err != nil { log.Fatalf("Error saving public key: %v\n", err) } @@ -76,7 +76,7 @@ func SignECCCmd(cmd *cobra.Command, args []string) { // Save the signature to a file in the data folder (optional, based on the input file) if keyDir != "" { signatureFilePath := fmt.Sprintf("%s/%s-signature.sig", keyDir, uniqueID.String()) - err = ECCrypto.SaveSignatureToFile(signatureFilePath, signature) + err = EC.SaveSignatureToFile(signatureFilePath, signature) if err != nil { log.Fatalf("Error saving signature: %v\n", err) } @@ -91,7 +91,7 @@ func VerifyECCCmd(cmd *cobra.Command, args []string) { signatureFile, _ := cmd.Flags().GetString("signature") // Path to signature file // ECC implementation - ECCrypto := &cryptography.ECCrypto{} + EC := &cryptography.EC{} var publicKey *ecdsa.PublicKey var err error @@ -99,7 +99,7 @@ func VerifyECCCmd(cmd *cobra.Command, args []string) { if publicKeyPath == "" { log.Fatalf("Public key is required for ECC signature verification.\n") } else { - publicKey, err = ECCrypto.ReadPublicKey(publicKeyPath, elliptic.P256()) + publicKey, err = EC.ReadPublicKey(publicKeyPath, elliptic.P256()) if err != nil { log.Fatalf("Error reading public key: %v\n", err) } @@ -124,7 +124,7 @@ func VerifyECCCmd(cmd *cobra.Command, args []string) { } // Verify the signature - valid, err := ECCrypto.Verify(fileContent, signature, publicKey) + valid, err := EC.Verify(fileContent, signature, publicKey) if err != nil { log.Fatalf("Error verifying signature: %v\n", err) } diff --git a/cmd/crypto-vault-cli/internal/commands/rsa-commands.go b/cmd/crypto-vault-cli/internal/commands/rsa-commands.go index 2613dd0..a0fe599 100644 --- a/cmd/crypto-vault-cli/internal/commands/rsa-commands.go +++ b/cmd/crypto-vault-cli/internal/commands/rsa-commands.go @@ -25,7 +25,7 @@ func EncryptRSACmd(cmd *cobra.Command, args []string) { // Generate RSA keys if no public key is provided var publicKey *rsa.PublicKey var err error - rsa := &cryptography.RSACrypto{} + rsa := &cryptography.RSA{} uniqueID := uuid.New() // Generate RSA keys @@ -78,7 +78,7 @@ func DecryptRSACmd(cmd *cobra.Command, args []string) { // Generate RSA keys if no private key is provided var privateKey *rsa.PrivateKey var err error - rsa := &cryptography.RSACrypto{} + rsa := &cryptography.RSA{} if privateKeyPath == "" { // Generate RSA keys privKey, _, genErr := rsa.GenerateKeys(2048) diff --git a/docs/diagrams/erd.mmd b/docs/diagrams/erd.mmd index 774f779..12a8496 100644 --- a/docs/diagrams/erd.mmd +++ b/docs/diagrams/erd.mmd @@ -1,12 +1,13 @@ erDiagram - CRYPTOGRAPHIC_KEY { + CRYPTO_KEY_META { string id PK + string algorithm string type datetime date_time_created string user_id FK } - BLOB { + BLOB_META { string id PK datetime date_time_created string user_id FK @@ -18,4 +19,4 @@ erDiagram string hash_algorithm } - CRYPTOGRAPHIC_KEY ||--o| BLOB : "associated with" + CRYPTO_KEY_META ||--o| BLOB_META : "associated with" diff --git a/internal/app/services/blob_services.go b/internal/app/services/blob_services.go index 1b6d092..b8b85c3 100644 --- a/internal/app/services/blob_services.go +++ b/internal/app/services/blob_services.go @@ -25,28 +25,27 @@ func NewBlobUploadService(blobConnector connector.BlobConnector, blobRepository func (s *BlobUploadService) Upload(filePaths []string, userId string) ([]*blobs.BlobMeta, error) { // Use the BlobConnector to upload the files to Azure Blob Storage - blobMeta, err := s.BlobConnector.Upload(filePaths, userId) + blobMetas, err := s.BlobConnector.Upload(filePaths, userId) if err != nil { return nil, fmt.Errorf("failed to upload blobs: %w", err) } // If no blobs are uploaded, return early - if len(blobMeta) == 0 { + if len(blobMetas) == 0 { return nil, fmt.Errorf("no blobs uploaded") } // Store the metadata in the database using the BlobRepository - for _, blob := range blobMeta { - err := s.BlobRepository.Create(blob) + for _, blobMeta := range blobMetas { + err := s.BlobRepository.Create(blobMeta) if err != nil { // Rollback any previously uploaded blobs if the metadata fails to store // (you can call delete method to handle this as needed) - return nil, fmt.Errorf("failed to store metadata for blob '%s': %w", blob.Name, err) + return nil, fmt.Errorf("failed to store metadata for blob '%s': %w", blobMeta.Name, err) } } - // Return the metadata of uploaded blobs - return blobMeta, nil + return blobMetas, nil } // BlobMetadataService implements the BlobMetadataService interface for retrieving and deleting blob metadata @@ -66,27 +65,27 @@ func NewBlobMetadataService(blobRepository repository.BlobRepository, blobConnec // List retrieves all blobs' metadata considering a query filter func (s *BlobMetadataService) List(query *blobs.BlobMetaQuery) ([]*blobs.BlobMeta, error) { // Assuming BlobRepository has a method to query metadata, you can adapt to GORM queries. - var blobsList []*blobs.BlobMeta + var blobMetas []*blobs.BlobMeta // TBD - return blobsList, nil + return blobMetas, nil } // GetByID retrieves a blob's metadata by its unique ID func (s *BlobMetadataService) GetByID(blobID string) (*blobs.BlobMeta, error) { // Retrieve the blob metadata using the BlobRepository - blob, err := s.BlobRepository.GetById(blobID) + blobMeta, err := s.BlobRepository.GetById(blobID) if err != nil { return nil, fmt.Errorf("failed to retrieve blob metadata by ID '%s': %w", blobID, err) } - return blob, nil + return blobMeta, nil } // DeleteByID deletes a blob and its associated metadata by ID func (s *BlobMetadataService) DeleteByID(blobID string) error { // Retrieve the blob metadata to ensure it exists - blob, err := s.BlobRepository.GetById(blobID) + blobMeta, err := s.BlobRepository.GetById(blobID) if err != nil { return fmt.Errorf("failed to retrieve blob metadata by ID '%s' for deletion: %w", blobID, err) } @@ -98,9 +97,9 @@ func (s *BlobMetadataService) DeleteByID(blobID string) error { } // Now, delete the actual blob from the Blob Storage - err = s.BlobConnector.Delete(blob.ID, blob.Name) + err = s.BlobConnector.Delete(blobMeta.ID, blobMeta.Name) if err != nil { - return fmt.Errorf("failed to delete blob '%s' from Blob Storage: %w", blob.Name, err) + return fmt.Errorf("failed to delete blob '%s' from Blob Storage: %w", blobMeta.Name, err) } return nil @@ -127,6 +126,5 @@ func (s *BlobDownloadService) Download(blobID, blobName string) ([]byte, error) return nil, fmt.Errorf("failed to download blob '%s': %w", blobName, err) } - // Return the metadata and content of the downloaded blob return blob, nil } diff --git a/internal/app/services/key_services.go b/internal/app/services/key_services.go index dc6a8de..a2c1527 100644 --- a/internal/app/services/key_services.go +++ b/internal/app/services/key_services.go @@ -5,51 +5,26 @@ import ( "crypto_vault_service/internal/infrastructure/connector" "crypto_vault_service/internal/persistence/repository" "fmt" - "time" - - "github.com/google/uuid" ) -type CryptKeyUploadService struct { +type CryptoKeyUploadService struct { VaultConnector connector.VaultConnector CryptoKeyRepo repository.CryptoKeyRepository } -func (s *CryptKeyUploadService) Upload(filePaths []string) ([]*keys.CryptoKeyMeta, error) { +func (s *CryptoKeyUploadService) Upload(filePath, userId, keyType, keyAlgorihm string) (*keys.CryptoKeyMeta, error) { // Step 1: Upload files to blob storage - userId := uuid.New().String() - blobMeta, err := s.VaultConnector.Upload(filePaths, userId) + keyMeta, err := s.VaultConnector.Upload(filePath, userId, keyType, keyAlgorihm) if err != nil { return nil, fmt.Errorf("failed to upload files: %w", err) } // Step 2: Store the metadata in the database - var keyMetas []*keys.CryptoKeyMeta - for _, blob := range blobMeta { - // Map Blob metadata to CryptoKey metadata - keyMeta := &keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "RSA", // Example key type - DateTimeCreated: time.Now(), // Valid DateTimeCreated time - UserID: uuid.New().String(), // Generate valid UUID for UserID - } - - // Validate CryptoKeyMeta - if err := keyMeta.Validate(); err != nil { - return nil, fmt.Errorf("invalid key metadata: %w", err) - } - - // Save metadata to DB - if err := s.CryptoKeyRepo.Create(blob); err != nil { - return nil, fmt.Errorf("failed to create metadata for key of type %s: %w", keyMeta.Type, err) - } - - // Append to list - keyMetas = append(keyMetas, keyMeta) + if err := s.CryptoKeyRepo.Create(keyMeta); err != nil { + return nil, fmt.Errorf("failed to create metadata for key of type %s: %w", keyMeta.Type, err) } - // Return metadata - return keyMetas, nil + return keyMeta, nil } // CryptoKeyMetadataService manages cryptographic key metadata. @@ -59,7 +34,6 @@ type CryptoKeyMetadataService struct { // List retrieves all cryptographic key metadata based on a query. func (s *CryptoKeyMetadataService) List(query *keys.CryptoKeyQuery) ([]*keys.CryptoKeyMeta, error) { - // For now, let's just retrieve all metadata from the database var keyMetas []*keys.CryptoKeyMeta // TBD @@ -68,7 +42,6 @@ func (s *CryptoKeyMetadataService) List(query *keys.CryptoKeyQuery) ([]*keys.Cry // GetByID retrieves the metadata of a cryptographic key by its ID. func (s *CryptoKeyMetadataService) GetByID(keyID string) (*keys.CryptoKeyMeta, error) { - // Retrieve the metadata from the database keyMeta, err := s.CryptoKeyRepo.GetByID(keyID) if err != nil { return nil, fmt.Errorf("failed to retrieve key metadata: %w", err) @@ -93,24 +66,11 @@ type CryptoKeyDownloadService struct { } // Download retrieves a cryptographic key by its ID and type. -func (s *CryptoKeyDownloadService) Download(keyID string, keyType keys.KeyType) ([]byte, error) { - blobName := "" // Declare the variable outside the blocks - - if keyType == keys.AsymmetricPublic { - blobName = "asymmetric-public-key" // Assign to the already declared variable - } else if keyType == keys.AsymmetricPrivate { - blobName = "asymmetric-private-key" // Assign to the already declared variable - } else if keyType == keys.Symmetric { - blobName = "symmetric-key" // Assign to the already declared variable - } else { - return nil, fmt.Errorf("unsupported key type: %v", keyType) - } - - blobData, err := s.VaultConnector.Download(keyID, blobName) +func (s *CryptoKeyDownloadService) Download(keyID, keyType string) ([]byte, error) { + blobData, err := s.VaultConnector.Download(keyID, keyType) if err != nil { return nil, fmt.Errorf("failed to download key from blob storage: %w", err) } - // Return the metadata and the downloaded content (as a byte slice) return blobData, nil } diff --git a/internal/domain/blobs/models.go b/internal/domain/blobs/models.go index 43738e5..acc8ab9 100644 --- a/internal/domain/blobs/models.go +++ b/internal/domain/blobs/models.go @@ -37,5 +37,5 @@ func (b *BlobMeta) Validate() error { } return fmt.Errorf("Validation failed: %v", validationErrors) } - return nil // Return nil if validation passes + return nil } diff --git a/internal/domain/blobs/queries.go b/internal/domain/blobs/queries.go index d21de7e..70154d6 100644 --- a/internal/domain/blobs/queries.go +++ b/internal/domain/blobs/queries.go @@ -49,6 +49,5 @@ func (b *BlobMetaQuery) Validate() error { return fmt.Errorf("Validation failed: %v", validationErrors) } - // Return nil if no validation errors are found return nil } diff --git a/internal/domain/keys/contracts.go b/internal/domain/keys/contracts.go index 97fb1c4..5603c20 100644 --- a/internal/domain/keys/contracts.go +++ b/internal/domain/keys/contracts.go @@ -1,20 +1,10 @@ package keys -// KeyType defines a custom type for key types based on an integer. -type KeyType int - -// Enum-like values for different key types, using iota to generate sequential values. -const ( - AsymmetricPublic KeyType = iota // Public key in asymmetric cryptography (e.g., RSA, ECDSA) - AsymmetricPrivate // Private key in asymmetric cryptography (e.g., RSA, ECDSA) - Symmetric // Symmetric key (e.g., AES) -) - -// ICryptKeyUploadService defines methods for uploading cryptographic keys. -type ICryptKeyUploadService interface { +// ICryptoKeyUploadService defines methods for uploading cryptographic keys. +type ICryptoKeyUploadService interface { // Upload uploads cryptographic keys from specified file paths. // It returns a slice of CryptoKeyMeta and any error encountered during the upload process. - Upload(filePaths []string) ([]*CryptoKeyMeta, error) + Upload(filePath, userId, keyType, keyAlgorihm string) (*CryptoKeyMeta, error) } // ICryptoKeyMetadataService defines methods for managing cryptographic key metadata and deleting keys. @@ -36,5 +26,5 @@ type ICryptoKeyMetadataService interface { type ICryptoKeyDownloadService interface { // Download retrieves a cryptographic key by its ID and type. // It returns the CryptoKeyMeta, the key data as a byte slice, and any error encountered during the download process. - Download(keyID string, keyType KeyType) ([]byte, error) + Download(keyID, keyType string) ([]byte, error) } diff --git a/internal/domain/keys/models.go b/internal/domain/keys/models.go index bba959f..27d022b 100644 --- a/internal/domain/keys/models.go +++ b/internal/domain/keys/models.go @@ -9,10 +9,11 @@ import ( // CryptoKeyMeta represents the encryption key entity type CryptoKeyMeta struct { - ID string `gorm:"primaryKey" validate:"required,uuid4"` // ID is required and must be a valid UUID - Type string `validate:"required,oneof=AES RSA ECDSA"` // Type is required and must be one of the listed types - DateTimeCreated time.Time `validate:"required"` // DateTimeCreated is required - UserID string `gorm:"index" validate:"required,uuid4"` // UserID is required and must be a valid UUID + ID string `gorm:"primaryKey" validate:"required,uuid4"` // ID is required and must be a valid UUID + Algorithm string `validate:"omitempty,oneof=AES RSA EC"` // Type is required and must be one of the listed types + Type string `validate:"omitempty,oneof=private public symmetric"` // Type is required and must be one of the listed types + DateTimeCreated time.Time `validate:"required"` // DateTimeCreated is required + UserID string `gorm:"index" validate:"required,uuid4"` // UserID is required and must be a valid UUID } // Validate for validating CryptoKeyMeta struct @@ -30,5 +31,5 @@ func (k *CryptoKeyMeta) Validate() error { } return fmt.Errorf("Validation failed: %v", validationErrors) } - return nil // Return nil if validation passes + return nil } diff --git a/internal/domain/keys/queries.go b/internal/domain/keys/queries.go index 5a897f9..7fce16a 100644 --- a/internal/domain/keys/queries.go +++ b/internal/domain/keys/queries.go @@ -9,8 +9,9 @@ import ( // CryptoKeyQuery represents the parameters used to query encryption keys. type CryptoKeyQuery struct { - Type string `validate:"omitempty,oneof=AES RSA ECDSA"` // Type is optional but if provided, must be one of the listed types (AES, RSA, ECDSA) - DateTimeCreated time.Time `validate:"omitempty,gtefield=DateTimeCreated"` // DateTimeCreated is optional, but can be used for filtering + Algorithm string `validate:"omitempty,oneof=AES RSA EC"` // Type is optional but if provided, must be one of the listed types (AES, RSA, EC) + Type string `validate:"omitempty,oneof=private public symmetric"` // Type is optional but if provided, must be one of the listed types (private-key, public-key, symmetric-key) + DateTimeCreated time.Time `validate:"omitempty,gtefield=DateTimeCreated"` // DateTimeCreated is optional, but can be used for filtering // Pagination properties Limit int `validate:"omitempty,min=1"` // Limit is optional but if provided, should be at least 1 @@ -46,5 +47,5 @@ func (k *CryptoKeyQuery) Validate() error { } return fmt.Errorf("Validation failed: %v", validationErrors) } - return nil // Return nil if validation passes + return nil } diff --git a/internal/infrastructure/connector/blob_connectors.go b/internal/infrastructure/connector/blob_connectors.go index d08a311..cefd725 100644 --- a/internal/infrastructure/connector/blob_connectors.go +++ b/internal/infrastructure/connector/blob_connectors.go @@ -119,7 +119,6 @@ func (abc *AzureBlobConnector) Upload(filePaths []string, userId string) ([]*blo blobMeta = append(blobMeta, blob) } - // Return the list of blobs after successful upload. return blobMeta, nil } @@ -164,7 +163,6 @@ func (abc *AzureBlobConnector) Download(blobId, blobName string) ([]byte, error) return nil, fmt.Errorf("failed to close retryReader for blob '%s': %w", fullBlobName, err) } - // Return the buffer containing the downloaded data return downloadedData.Bytes(), nil } diff --git a/internal/infrastructure/connector/key_connectors.go b/internal/infrastructure/connector/key_connectors.go index 03fc837..e9ccacf 100644 --- a/internal/infrastructure/connector/key_connectors.go +++ b/internal/infrastructure/connector/key_connectors.go @@ -17,14 +17,15 @@ import ( // The current implementation uses Azure Blob Storage, but this may be replaced // with Azure Key Vault, AWS KMS, or any other cloud-based key management system in the future. type VaultConnector interface { - // Upload uploads multiple files to the Vault Storage and returns their metadata. - Upload(filePaths []string, userId string) ([]*keys.CryptoKeyMeta, error) + // Upload uploads single file to Azure Blob Storage and returns their metadata. + // In the future, this may be refactored to integrate with more advanced key storage systems like Azure Key Vault. + Upload(filePath, userId, keyType, keyAlgorihm string) (*keys.CryptoKeyMeta, error) // Download retrieves a key's content by its ID and name, and returns the data as a byte slice. - Download(blobId, blobName string) ([]byte, error) + Download(keyId, keyType string) ([]byte, error) // Delete deletes a key from Vault Storage by its ID and Name, and returns any error encountered. - Delete(blobId, blobName string) error + Delete(keyId, keyType string) error } // AzureVaultConnector is a struct that implements the VaultConnector interface using Azure Blob Storage. @@ -44,11 +45,9 @@ func NewAzureVaultConnector(connectionString string, containerName string) (*Azu return nil, fmt.Errorf("failed to create Azure Blob client: %w", err) } - // Ensure the container exists (this could be a simple placeholder, or it could be updated later to use a dedicated container for keys) _, err = client.CreateContainer(context.Background(), containerName, nil) if err != nil { - // Log container creation failure, but do not fail if container already exists - log.Printf("Failed to create Azure container: %v\n", err) + log.Printf("Failed to create Azure container: %v\n", err) // The container may already exist, so we should not return an error in this case. } return &AzureVaultConnector{ @@ -57,97 +56,82 @@ func NewAzureVaultConnector(connectionString string, containerName string) (*Azu }, nil } -// Upload uploads multiple files to Azure Blob Storage and returns their metadata. +// Upload uploads single file to Azure Blob Storage and returns their metadata. // In the future, this may be refactored to integrate with more advanced key storage systems like Azure Key Vault. -func (vc *AzureVaultConnector) Upload(filePaths []string, userId string) ([]*keys.CryptoKeyMeta, error) { - var keyMetas []*keys.CryptoKeyMeta - - // Iterate through all file paths and upload each file - for _, filePath := range filePaths { - // Open the file - file, err := os.Open(filePath) - if err != nil { - return nil, fmt.Errorf("failed to open file '%s': %w", filePath, err) - } - defer file.Close() - - // Get file information (name, size, etc.) - fileInfo, err := file.Stat() - if err != nil { - return nil, fmt.Errorf("failed to stat file '%s': %w", filePath, err) - } - - // Read the file content into a buffer - buf := new(bytes.Buffer) - _, err = buf.ReadFrom(file) - if err != nil { - return nil, fmt.Errorf("failed to read file '%s': %w", filePath, err) - } - - // Generate a unique ID for the key - keyID := uuid.New().String() - - // Create metadata for the uploaded key - keyMeta := &keys.CryptoKeyMeta{ - ID: keyID, - Type: fileInfo.Name(), // one of asymmetric-public-key, asymmetric-private-key, symmetric-key - DateTimeCreated: time.Now(), - UserID: userId, - } - - // Construct the full blob name (ID and Name) - fullBlobName := fmt.Sprintf("%s/%s", keyID, fileInfo.Name()) - - // Upload the blob (file) to Azure Blob Storage - _, err = vc.Client.UploadBuffer(context.Background(), vc.ContainerName, fullBlobName, buf.Bytes(), nil) - if err != nil { - return nil, fmt.Errorf("failed to upload blob '%s' to storage: %w", fullBlobName, err) - } - - // Add the metadata to the list - keyMetas = append(keyMetas, keyMeta) +func (vc *AzureVaultConnector) Upload(filePath, userId, keyType, keyAlgorihm string) (*keys.CryptoKeyMeta, error) { + // Open the file + file, err := os.Open(filePath) + if err != nil { + return nil, fmt.Errorf("failed to open file '%s': %w", filePath, err) + } + defer file.Close() + + // Read the file content into a buffer + buf := new(bytes.Buffer) + _, err = buf.ReadFrom(file) + if err != nil { + return nil, fmt.Errorf("failed to read file '%s': %w", filePath, err) + } + + // Generate a unique ID for the key + keyID := uuid.New().String() + + // Create metadata for the uploaded key + keyMeta := &keys.CryptoKeyMeta{ + ID: keyID, + Type: keyType, // one of public, private, symmetric + Algorithm: keyAlgorihm, + DateTimeCreated: time.Now(), + UserID: userId, + } + + // Construct the full blob name (ID and type) + fullKeyName := fmt.Sprintf("%s/%s", keyID, keyType) + + // Upload the blob (file) to Azure Blob Storage + _, err = vc.Client.UploadBuffer(context.Background(), vc.ContainerName, fullKeyName, buf.Bytes(), nil) + if err != nil { + return nil, fmt.Errorf("failed to upload blob '%s' to storage: %w", fullKeyName, err) } - // Return the metadata of the uploaded keys - return keyMetas, nil + return keyMeta, nil } // Download retrieves a key's content by its ID and name, and returns the data as a byte slice. -func (vc *AzureVaultConnector) Download(blobId, blobName string) ([]byte, error) { +func (vc *AzureVaultConnector) Download(keyId, keyType string) ([]byte, error) { // Construct the full blob path by combining blob ID and name - fullBlobName := fmt.Sprintf("%s/%s", blobId, blobName) + fullKeyName := fmt.Sprintf("%s/%s", keyId, keyType) // Download the blob from Azure Blob Storage ctx := context.Background() - get, err := vc.Client.DownloadStream(ctx, vc.ContainerName, fullBlobName, nil) + get, err := vc.Client.DownloadStream(ctx, vc.ContainerName, fullKeyName, nil) if err != nil { - return nil, fmt.Errorf("failed to download blob '%s': %w", fullBlobName, err) + return nil, fmt.Errorf("failed to download blob '%s': %w", fullKeyName, err) } // Read the content into a buffer downloadedData := bytes.Buffer{} _, err = downloadedData.ReadFrom(get.Body) if err != nil { - return nil, fmt.Errorf("failed to read data from blob '%s': %w", fullBlobName, err) + return nil, fmt.Errorf("failed to read data from blob '%s': %w", fullKeyName, err) } - // Return the downloaded data return downloadedData.Bytes(), nil } // Delete deletes a key from Azure Blob Storage by its ID and Name. -func (vc *AzureVaultConnector) Delete(blobId, blobName string) error { - // Construct the full blob path by combining blob ID and name - fullBlobName := fmt.Sprintf("%s/%s", blobId, blobName) +func (vc *AzureVaultConnector) Delete(keyId, keyType string) error { + // Construct the full blob path by combining blob ID and type + fullKeyName := fmt.Sprintf("%s/%s", keyId, keyType) // Delete the blob from Azure Blob Storage ctx := context.Background() - _, err := vc.Client.DeleteBlob(ctx, vc.ContainerName, fullBlobName, nil) + _, err := vc.Client.DeleteBlob(ctx, vc.ContainerName, fullKeyName, nil) if err != nil { - return fmt.Errorf("failed to delete blob '%s': %w", fullBlobName, err) + return fmt.Errorf("failed to delete blob '%s': %w", fullKeyName, err) } // Log the successful deletion - log.Printf("Deleted blob '%s' from storage.\n", fullBlobName) + log.Printf("Deleted blob '%s' from storage.\n", fullKeyName) return nil } diff --git a/internal/infrastructure/cryptography/aes.go b/internal/infrastructure/cryptography/aes.go index 4b902c9..46252bd 100644 --- a/internal/infrastructure/cryptography/aes.go +++ b/internal/infrastructure/cryptography/aes.go @@ -8,15 +8,15 @@ import ( "fmt" ) -// AES Interface -type AES interface { +// IAES Interface +type IAES interface { Encrypt(plainText, key []byte) ([]byte, error) Decrypt(ciphertext, key []byte) ([]byte, error) GenerateKey(keySize int) ([]byte, error) } -// AESCrypto struct that implements the AES interface -type AESCrypto struct{} +// AES struct that implements the IAES interface +type AES struct{} // Pad data to make it a multiple of AES block size func pkcs7Pad(data []byte, blockSize int) []byte { @@ -37,7 +37,7 @@ func pkcs7Unpad(data []byte, blockSize int) ([]byte, error) { } // GenerateRandomAESKey generates a random AES key of the specified size -func (a *AESCrypto) GenerateKey(keySize int) ([]byte, error) { +func (a *AES) GenerateKey(keySize int) ([]byte, error) { key := make([]byte, keySize) _, err := rand.Read(key) if err != nil { @@ -47,7 +47,7 @@ func (a *AESCrypto) GenerateKey(keySize int) ([]byte, error) { } // Encrypt data using AES in CBC mode -func (a *AESCrypto) Encrypt(plainText, key []byte) ([]byte, error) { +func (a *AES) Encrypt(plainText, key []byte) ([]byte, error) { if key == nil { return nil, fmt.Errorf("key key cannot be nil") } @@ -72,7 +72,7 @@ func (a *AESCrypto) Encrypt(plainText, key []byte) ([]byte, error) { } // Decrypt data using AES in CBC mode -func (a *AESCrypto) Decrypt(ciphertext, key []byte) ([]byte, error) { +func (a *AES) Decrypt(ciphertext, key []byte) ([]byte, error) { if key == nil { return nil, fmt.Errorf("key key cannot be nil") } diff --git a/internal/infrastructure/cryptography/ecdsa.go b/internal/infrastructure/cryptography/ec.go similarity index 86% rename from internal/infrastructure/cryptography/ecdsa.go rename to internal/infrastructure/cryptography/ec.go index 89bb520..0cd3576 100644 --- a/internal/infrastructure/cryptography/ecdsa.go +++ b/internal/infrastructure/cryptography/ec.go @@ -12,8 +12,8 @@ import ( "os" ) -// EC Interface -type EC interface { +// IEC Interface +type IEC interface { GenerateKeys(curve elliptic.Curve) (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) Sign(message []byte, privateKey *ecdsa.PrivateKey) ([]byte, error) Verify(message, signature []byte, publicKey *ecdsa.PublicKey) (bool, error) @@ -24,11 +24,11 @@ type EC interface { ReadPublicKey(publicKeyPath string) (*ecdsa.PublicKey, error) } -// ECCrypto struct that implements the EC interface -type ECCrypto struct{} +// EC struct that implements the IEC interface +type EC struct{} // GenerateKeys generates an elliptic curve key pair -func (e *ECCrypto) GenerateKeys(curve elliptic.Curve) (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) { +func (e *EC) GenerateKeys(curve elliptic.Curve) (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) { privateKey, err := ecdsa.GenerateKey(curve, rand.Reader) if err != nil { return nil, nil, fmt.Errorf("failed to generate elliptic curve keys: %v", err) @@ -39,7 +39,7 @@ func (e *ECCrypto) GenerateKeys(curve elliptic.Curve) (*ecdsa.PrivateKey, *ecdsa } // Sign signs a message with the private key -func (e *ECCrypto) Sign(message []byte, privateKey *ecdsa.PrivateKey) ([]byte, error) { +func (e *EC) Sign(message []byte, privateKey *ecdsa.PrivateKey) ([]byte, error) { if privateKey == nil { return nil, fmt.Errorf("private key cannot be nil") } @@ -62,7 +62,7 @@ func (e *ECCrypto) Sign(message []byte, privateKey *ecdsa.PrivateKey) ([]byte, e } // Verify verifies the signature of a message with the public key -func (e *ECCrypto) Verify(message, signature []byte, publicKey *ecdsa.PublicKey) (bool, error) { +func (e *EC) Verify(message, signature []byte, publicKey *ecdsa.PublicKey) (bool, error) { if publicKey == nil { return false, fmt.Errorf("public key cannot be nil") } @@ -81,7 +81,7 @@ func (e *ECCrypto) Verify(message, signature []byte, publicKey *ecdsa.PublicKey) } // SavePrivateKeyToFile saves the private key to a PEM file using encoding/pem -func (e *ECCrypto) SavePrivateKeyToFile(privateKey *ecdsa.PrivateKey, filename string) error { +func (e *EC) SavePrivateKeyToFile(privateKey *ecdsa.PrivateKey, filename string) error { // Marshal private key components (private key 'D' and public key components 'X' and 'Y') privKeyBytes := append(privateKey.D.Bytes(), privateKey.PublicKey.X.Bytes()...) privKeyBytes = append(privKeyBytes, privateKey.PublicKey.Y.Bytes()...) @@ -109,7 +109,7 @@ func (e *ECCrypto) SavePrivateKeyToFile(privateKey *ecdsa.PrivateKey, filename s } // SavePublicKeyToFile saves the public key to a PEM file using encoding/pem -func (e *ECCrypto) SavePublicKeyToFile(publicKey *ecdsa.PublicKey, filename string) error { +func (e *EC) SavePublicKeyToFile(publicKey *ecdsa.PublicKey, filename string) error { pubKeyBytes := append(publicKey.X.Bytes(), publicKey.Y.Bytes()...) // Prepare the PEM block for the public key @@ -135,7 +135,7 @@ func (e *ECCrypto) SavePublicKeyToFile(publicKey *ecdsa.PublicKey, filename stri } // SaveSignatureToFile can be used for storing signature files in hex format -func (e *ECCrypto) SaveSignatureToFile(filename string, data []byte) error { +func (e *EC) SaveSignatureToFile(filename string, data []byte) error { hexData := hex.EncodeToString(data) err := os.WriteFile(filename, []byte(hexData), 0644) if err != nil { @@ -145,7 +145,7 @@ func (e *ECCrypto) SaveSignatureToFile(filename string, data []byte) error { } // ReadPrivateKey reads an ECDSA private key from a PEM file using encoding/pem -func (e *ECCrypto) ReadPrivateKey(privateKeyPath string, curve elliptic.Curve) (*ecdsa.PrivateKey, error) { +func (e *EC) ReadPrivateKey(privateKeyPath string, curve elliptic.Curve) (*ecdsa.PrivateKey, error) { privKeyPEM, err := os.ReadFile(privateKeyPath) if err != nil { return nil, fmt.Errorf("unable to read private key file: %v", err) @@ -178,7 +178,7 @@ func (e *ECCrypto) ReadPrivateKey(privateKeyPath string, curve elliptic.Curve) ( } // ReadPublicKey reads an ECDSA public key from a PEM file using encoding/pem -func (e *ECCrypto) ReadPublicKey(publicKeyPath string, curve elliptic.Curve) (*ecdsa.PublicKey, error) { +func (e *EC) ReadPublicKey(publicKeyPath string, curve elliptic.Curve) (*ecdsa.PublicKey, error) { pubKeyPEM, err := os.ReadFile(publicKeyPath) if err != nil { return nil, fmt.Errorf("unable to read public key file: %v", err) diff --git a/internal/infrastructure/cryptography/pkcs11.go b/internal/infrastructure/cryptography/pkcs11.go index 2eaaaed..61a4619 100644 --- a/internal/infrastructure/cryptography/pkcs11.go +++ b/internal/infrastructure/cryptography/pkcs11.go @@ -7,8 +7,8 @@ import ( "strings" ) -// PKCS11Token defines the operations for working with a PKCS#11 token -type PKCS11Token interface { +// IPKCS11TokenHandler defines the operations for working with a PKCS#11 token +type IPKCS11TokenHandler interface { IsTokenSet() (bool, error) IsObjectSet() (bool, error) InitializeToken(slot string) error diff --git a/internal/infrastructure/cryptography/rsa.go b/internal/infrastructure/cryptography/rsa.go index b46de1f..e910232 100644 --- a/internal/infrastructure/cryptography/rsa.go +++ b/internal/infrastructure/cryptography/rsa.go @@ -10,8 +10,8 @@ import ( "os" ) -// RSA Interface -type RSA interface { +// IRSA Interface +type IRSA interface { Encrypt(plainText []byte, publicKey *rsa.PublicKey) ([]byte, error) Decrypt(ciphertext []byte, privateKey *rsa.PrivateKey) ([]byte, error) GenerateKeys(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) @@ -21,11 +21,11 @@ type RSA interface { ReadPublicKey(publicKeyPath string) (*rsa.PublicKey, error) } -// RSACrypto struct that implements the RSA interface -type RSACrypto struct{} +// RSA struct that implements the IRSA interface +type RSA struct{} // GenerateRSAKeys generates RSA key pair -func (r *RSACrypto) GenerateKeys(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) { +func (r *RSA) GenerateKeys(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) { privateKey, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { return nil, nil, fmt.Errorf("failed to generate RSA keys: %v", err) @@ -35,7 +35,7 @@ func (r *RSACrypto) GenerateKeys(bits int) (*rsa.PrivateKey, *rsa.PublicKey, err } // Encrypt data using RSA public key -func (r *RSACrypto) Encrypt(plainText []byte, publicKey *rsa.PublicKey) ([]byte, error) { +func (r *RSA) Encrypt(plainText []byte, publicKey *rsa.PublicKey) ([]byte, error) { if publicKey == nil { return nil, errors.New("public key cannot be nil") } @@ -48,7 +48,7 @@ func (r *RSACrypto) Encrypt(plainText []byte, publicKey *rsa.PublicKey) ([]byte, } // Decrypt data using RSA private key -func (r *RSACrypto) Decrypt(ciphertext []byte, privateKey *rsa.PrivateKey) ([]byte, error) { +func (r *RSA) Decrypt(ciphertext []byte, privateKey *rsa.PrivateKey) ([]byte, error) { if privateKey == nil { return nil, fmt.Errorf("private key cannot be nil") } @@ -60,7 +60,7 @@ func (r *RSACrypto) Decrypt(ciphertext []byte, privateKey *rsa.PrivateKey) ([]by return decryptedData, nil } -func (r *RSACrypto) SavePrivateKeyToFile(privateKey *rsa.PrivateKey, filename string) error { +func (r *RSA) SavePrivateKeyToFile(privateKey *rsa.PrivateKey, filename string) error { privKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey) privKeyPem := &pem.Block{ Type: "RSA PRIVATE KEY", @@ -81,7 +81,7 @@ func (r *RSACrypto) SavePrivateKeyToFile(privateKey *rsa.PrivateKey, filename st return nil } -func (r *RSACrypto) SavePublicKeyToFile(publicKey *rsa.PublicKey, filename string) error { +func (r *RSA) SavePublicKeyToFile(publicKey *rsa.PublicKey, filename string) error { pubKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey) if err != nil { return fmt.Errorf("failed to marshal public key: %v", err) @@ -107,7 +107,7 @@ func (r *RSACrypto) SavePublicKeyToFile(publicKey *rsa.PublicKey, filename strin } // Read RSA private key from PEM file -func (r *RSACrypto) ReadPrivateKey(privateKeyPath string) (*rsa.PrivateKey, error) { +func (r *RSA) ReadPrivateKey(privateKeyPath string) (*rsa.PrivateKey, error) { privKeyPEM, err := os.ReadFile(privateKeyPath) if err != nil { return nil, fmt.Errorf("unable to read private key file: %v", err) @@ -140,7 +140,7 @@ func (r *RSACrypto) ReadPrivateKey(privateKeyPath string) (*rsa.PrivateKey, erro } // Read RSA public key from PEM file -func (r *RSACrypto) ReadPublicKey(publicKeyPath string) (*rsa.PublicKey, error) { +func (r *RSA) ReadPublicKey(publicKeyPath string) (*rsa.PublicKey, error) { pubKeyPEM, err := os.ReadFile(publicKeyPath) if err != nil { return nil, fmt.Errorf("unable to read public key file: %v", err) diff --git a/test/unit/app/services/mocks.go b/test/helpers/mocks.go similarity index 99% rename from test/unit/app/services/mocks.go rename to test/helpers/mocks.go index e5f0b6c..6010f5a 100644 --- a/test/unit/app/services/mocks.go +++ b/test/helpers/mocks.go @@ -1,4 +1,4 @@ -package services +package helpers import ( "crypto_vault_service/internal/domain/blobs" diff --git a/test/helpers/test_db_context.go b/test/helpers/test_db_context.go new file mode 100644 index 0000000..2e6a176 --- /dev/null +++ b/test/helpers/test_db_context.go @@ -0,0 +1,129 @@ +package helpers + +import ( + "crypto_vault_service/internal/domain/blobs" + "crypto_vault_service/internal/domain/keys" + "crypto_vault_service/internal/persistence/repository" + "fmt" + "os" + "testing" + + "github.com/google/uuid" + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +type TestDBContext struct { + DB *gorm.DB + BlobRepo *repository.GormBlobRepository + CryptoKeyRepo *repository.GormCryptoKeyRepository +} + +// SetupTestDB initializes the test database and repositories based on the DB_TYPE environment variable +func SetupTestDB(t *testing.T) *TestDBContext { + var err error + var db *gorm.DB + + dbType := os.Getenv("DB_TYPE") + if dbType == "" { + dbType = "sqlite" // Default to SQLite in-memory if DB_TYPE is not set + } + + switch dbType { + case "postgres": + // PostgreSQL setup + dsn := "user=postgres password=postgres host=localhost port=5432 sslmode=disable" + if dsn == "" { + t.Fatalf("POSTGRES_DSN environment variable is not set") + } + + // Connect to PostgreSQL without specifying a database (so we can create one if necessary) + db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + t.Fatalf("Failed to connect to PostgreSQL: %v", err) + } + + // Generate a unique database name using UUID + uniqueDBName := "blobs_" + uuid.New().String() + + // Ensure the unique `blobs` database exists, create if necessary + sqlDB, err := db.DB() + if err != nil { + t.Fatalf("Failed to get raw DB connection: %v", err) + } + + // Create the new database + _, err = sqlDB.Exec(fmt.Sprintf("CREATE DATABASE %s", uniqueDBName)) + if err != nil { + t.Fatalf("Failed to create database '%s': %v", uniqueDBName, err) + } + fmt.Printf("Database '%s' created successfully.\n", uniqueDBName) + + // Now that the unique `blobs` database is created, connect to it + dsn = fmt.Sprintf("user=postgres password=postgres host=localhost port=5432 dbname=%s sslmode=disable", uniqueDBName) + db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + t.Fatalf("Failed to connect to PostgreSQL database '%s': %v", uniqueDBName, err) + } + + case "sqlite": + db, err = gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) + if err != nil { + t.Fatalf("Failed to connect to SQLite: %v", err) + } + + default: + t.Fatalf("Unsupported DB_TYPE value: %s", dbType) + } + + // Migrate the schema for Blob and CryptoKey + err = db.AutoMigrate(&blobs.BlobMeta{}, &keys.CryptoKeyMeta{}) + if err != nil { + t.Fatalf("Failed to migrate schema: %v", err) + } + + // Initialize the repositories with the DB instance + blobRepo := &repository.GormBlobRepository{DB: db} + cryptoKeyRepo := &repository.GormCryptoKeyRepository{DB: db} + + return &TestDBContext{ + DB: db, + BlobRepo: blobRepo, + CryptoKeyRepo: cryptoKeyRepo, + } +} + +// TeardownTestDB closes the DB connection and cleans up the database after the test +func TeardownTestDB(t *testing.T, ctx *TestDBContext, dbType string) { + sqlDB, err := ctx.DB.DB() + if err != nil { + t.Fatalf("Failed to get DB connection: %v", err) + } + + // If using PostgreSQL, drop the unique database created during the test + if dbType == "postgres" { + // Get the database name from the DSN or context (you might store it during DB setup) + databaseName := ctx.DB.Migrator().CurrentDatabase() + + // Close the current DB connection before dropping the database + sqlDB.Close() + + // Connect again to PostgreSQL without specifying a database (connect to the default one) + dsn := "user=postgres password=postgres host=localhost port=5432 sslmode=disable" + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + t.Fatalf("Failed to reconnect to PostgreSQL: %v", err) + } + + // Drop the unique database + tx := db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", databaseName)) + if tx.Error != nil { + t.Fatalf("Failed to drop database '%s': %v", databaseName, tx.Error) + } + fmt.Printf("Database '%s' dropped successfully.\n", databaseName) + } else { + // For SQLite, no need to drop the in-memory database, just close the connection + sqlDB.Close() + } +} diff --git a/test/integration/app/services/key_services_test.go b/test/integration/app/services/key_services_test.go new file mode 100644 index 0000000..c093e01 --- /dev/null +++ b/test/integration/app/services/key_services_test.go @@ -0,0 +1,206 @@ +package services + +import ( + "crypto_vault_service/internal/app/services" + "crypto_vault_service/internal/domain/keys" + "crypto_vault_service/internal/infrastructure/connector" + "crypto_vault_service/test/helpers" + "fmt" + "os" + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/require" + "gorm.io/gorm" +) + +// Helper function to create a test file +func createTestFile(testFilePath string, testFileContent []byte) error { + err := os.WriteFile(testFilePath, testFileContent, 0644) + if err != nil { + return fmt.Errorf("failed to create test file at %s: %v", testFilePath, err) + } + return nil +} + +// Helper function to remove the test file +func removeTestFile(testFilePath string) error { + err := os.Remove(testFilePath) + if err != nil { + return fmt.Errorf("failed to remove test file at %s: %v", testFilePath, err) + } + return nil +} + +// Test case for successful file upload and metadata creation +func TestCryptoKeyUploadService_Upload_Success(t *testing.T) { + // Set up test context + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) + + // Initialize Vault Connector + connectionString := "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" + containerName := "testblobs" + vaultConnector, err := connector.NewAzureVaultConnector(connectionString, containerName) + require.NoError(t, err, "Error creating vault connector") + + // Set up the CryptoKeyUploadService + cryptoKeyUploadService := &services.CryptoKeyUploadService{ + VaultConnector: vaultConnector, + CryptoKeyRepo: ctx.CryptoKeyRepo, + } + + // Prepare test file + testFilePath := "testfile.pem" + testFileContent := []byte("This is a test file content.") + err = createTestFile(testFilePath, testFileContent) + require.NoError(t, err, "Error creating test file") + defer func() { + err := removeTestFile(testFilePath) + require.NoError(t, err, "Error deleting test file") + }() + + // Call the method under test + userId := uuid.New().String() + keyType := "private" + keyAlgorithm := "EC" + keyMeta, err := cryptoKeyUploadService.Upload(testFilePath, userId, keyType, keyAlgorithm) + + // Assert that no error occurred during the upload + require.NoError(t, err, "Error uploading file") + + // Assert that keyMeta is not nil and contains expected data + require.NotNil(t, keyMeta, "Key metadata should not be nil") + require.NotEmpty(t, keyMeta.ID, "KeyID should not be empty") + require.Equal(t, userId, keyMeta.UserID, "UserID does not match") +} + +// Test case for successful retrieval of cryptographic key metadata by ID +func TestCryptoKeyMetadataService_GetByID_Success(t *testing.T) { + // Set up test context + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) + + // Create a key metadata instance in the database for testing + cryptoKeyMeta := &keys.CryptoKeyMeta{ + ID: uuid.New().String(), + Type: "public", + Algorithm: "EC", + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), + } + + // Store the cryptographic key metadata in the database + err := ctx.CryptoKeyRepo.Create(cryptoKeyMeta) + require.NoError(t, err, "Error creating test cryptographic key metadata") + + // Set up the CryptoKeyMetadataService + cryptoKeyMetadataService := &services.CryptoKeyMetadataService{ + CryptoKeyRepo: ctx.CryptoKeyRepo, + } + + // Call the method under test + fetchedCryptoKeyMeta, err := cryptoKeyMetadataService.GetByID(cryptoKeyMeta.ID) + + // Assert that no error occurred during retrieval + require.NoError(t, err, "Error retrieving cryptographic key metadata") + + // Assert that the fetched metadata matches the original + require.NotNil(t, fetchedCryptoKeyMeta, "Fetched cryptographic key metadata should not be nil") + require.Equal(t, cryptoKeyMeta.ID, fetchedCryptoKeyMeta.ID, "ID should match") + require.Equal(t, cryptoKeyMeta.Type, fetchedCryptoKeyMeta.Type, "Type should match") + require.Equal(t, cryptoKeyMeta.Algorithm, fetchedCryptoKeyMeta.Algorithm, "Algorithm should match") +} + +// Test case for successful deletion of cryptographic key metadata by ID +func TestCryptoKeyMetadataService_DeleteByID_Success(t *testing.T) { + // Set up test context + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) + + // Create a key metadata instance in the database for testing + cryptoKeyMeta := &keys.CryptoKeyMeta{ + ID: uuid.New().String(), + Type: "private", + Algorithm: "RSA", + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), + } + + // Store the cryptographic key metadata in the database + err := ctx.CryptoKeyRepo.Create(cryptoKeyMeta) + require.NoError(t, err, "Error creating test cryptographic key metadata") + + // Set up the CryptoKeyMetadataService + cryptoKeyMetadataService := &services.CryptoKeyMetadataService{ + CryptoKeyRepo: ctx.CryptoKeyRepo, + } + + // Call the method under test + err = cryptoKeyMetadataService.DeleteByID(cryptoKeyMeta.ID) + + // Assert that no error occurred during deletion + require.NoError(t, err, "Error deleting cryptographic key metadata") + + // Verify the metadata is deleted + var deletedCryptoKeyMeta keys.CryptoKeyMeta + err = ctx.DB.First(&deletedCryptoKeyMeta, "id = ?", cryptoKeyMeta.ID).Error + require.Error(t, err, "Cryptographic key metadata should be deleted") + require.Equal(t, gorm.ErrRecordNotFound, err, "Error should be 'record not found'") +} + +// Test case for successful download of cryptographic key +func TestCryptoKeyDownloadService_Download_Success(t *testing.T) { + // Set up test context + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) + + // Initialize Vault Connector + connectionString := "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" + containerName := "testblobs" + vaultConnector, err := connector.NewAzureVaultConnector(connectionString, containerName) + require.NoError(t, err, "Error creating vault connector") + + // Set up the CryptoKeyUploadService + cryptoKeyUploadService := &services.CryptoKeyUploadService{ + VaultConnector: vaultConnector, + CryptoKeyRepo: ctx.CryptoKeyRepo, + } + + // Prepare test file + testFilePath := "testfile.pem" + testFileContent := []byte("This is a test file content.") + err = createTestFile(testFilePath, testFileContent) + require.NoError(t, err, "Error creating test file") + defer func() { + err := removeTestFile(testFilePath) + require.NoError(t, err, "Error deleting test file") + }() + + // Call the method under test + userId := uuid.New().String() + keyType := "private" + keyAlgorithm := "EC" + cryptoKeyMeta, err := cryptoKeyUploadService.Upload(testFilePath, userId, keyType, keyAlgorithm) + require.NoError(t, err, "Error uploading file") + + // Set up the CryptoKeyDownloadService + cryptoKeyDownloadService := &services.CryptoKeyDownloadService{ + VaultConnector: vaultConnector, + } + + // Call the method under test + blobData, err := cryptoKeyDownloadService.Download(cryptoKeyMeta.ID, keyType) + + // Assert that no error occurred during download + require.NoError(t, err, "Error downloading cryptographic key") + + // Assert that blobData is not nil or empty + require.NotNil(t, blobData, "Downloaded key data should not be nil") + require.NotEmpty(t, blobData, "Downloaded key data should not be empty") +} diff --git a/test/integration/infrastructure/connector/az_blob_connector_test.go b/test/integration/infrastructure/connector/az_blob_connector_test.go index 649d9a3..0ef7336 100644 --- a/test/integration/infrastructure/connector/az_blob_connector_test.go +++ b/test/integration/infrastructure/connector/az_blob_connector_test.go @@ -11,119 +11,115 @@ import ( "github.com/stretchr/testify/require" ) -// Define a struct for the test context to reuse across multiple tests -type AzureBlobTest struct { - Connector *connector.AzureBlobConnector - TestFilePath string - TestFileContent []byte - ContainerName string -} - -// Helper function to create a test file -func (abt *AzureBlobTest) createTestFile(t *testing.T) { - err := os.WriteFile(abt.TestFilePath, abt.TestFileContent, 0644) - require.NoError(t, err) -} - -// Helper function to remove the test file -func (abt *AzureBlobTest) removeTestFile(t *testing.T) { - err := os.Remove(abt.TestFilePath) - require.NoError(t, err) -} - -// Helper function to create a new AzureBlobTest instance -func NewAzureBlobTest(t *testing.T) *AzureBlobTest { +// TestAzureBlobConnector_Upload tests the Upload method of AzureBlobConnector +func TestAzureBlobConnector_Upload(t *testing.T) { + // Prepare environment and initialize the connector connectionString := "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" containerName := "testblobs" abc, err := connector.NewAzureBlobConnector(connectionString, containerName) require.NoError(t, err) - return &AzureBlobTest{ - Connector: abc, - TestFilePath: "testfile.txt", - TestFileContent: []byte("This is a test file content."), - ContainerName: containerName, - } -} + // Prepare test file content + testFilePath := "testfile.txt" + testFileContent := []byte("This is a test file content.") -// TestUpload tests the Upload method of AzureBlobConnector -func TestUpload(t *testing.T) { - // Initialize test struct - azureTest := NewAzureBlobTest(t) + // Create test file + err = os.WriteFile(testFilePath, testFileContent, 0644) + require.NoError(t, err) - // Prepare test file - azureTest.createTestFile(t) + // Clean up the test file after the test + defer os.Remove(testFilePath) // Upload the file userId := uuid.New().String() - blobs, err := azureTest.Connector.Upload([]string{azureTest.TestFilePath}, userId) + filePaths := []string{testFilePath} + blobs, err := abc.Upload(filePaths, userId) require.NoError(t, err) // Assert that we received one blob metadata assert.Len(t, blobs, 1) blob := blobs[0] assert.NotEmpty(t, blob.ID) - assert.Equal(t, "testfile.txt", blob.Name) - assert.Equal(t, int64(len(azureTest.TestFileContent)), blob.Size) + assert.Equal(t, testFilePath, blob.Name) + assert.Equal(t, int64(len(testFileContent)), blob.Size) assert.Equal(t, ".txt", blob.Type) - // Clean up the test file and blob - azureTest.removeTestFile(t) - err = azureTest.Connector.Delete(blob.ID, blob.Name) + // Delete the uploaded blob + err = abc.Delete(blob.ID, blob.Name) require.NoError(t, err) } -// TestDownload tests the Download method of AzureBlobConnector -func TestDownload(t *testing.T) { - // Initialize test struct - azureTest := NewAzureBlobTest(t) +// TestAzureBlobConnector_Download tests the Download method of AzureBlobConnector +func TestAzureBlobConnector_Download(t *testing.T) { + // Prepare environment and initialize the connector + connectionString := "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" + containerName := "testblobs" + abc, err := connector.NewAzureBlobConnector(connectionString, containerName) + require.NoError(t, err) + + // Prepare test file content + testFilePath := "testfile.pem" + testFileContent := []byte("This is a test file content.") + + // Create test file + err = os.WriteFile(testFilePath, testFileContent, 0644) + require.NoError(t, err) - // Prepare test file - azureTest.createTestFile(t) + // Clean up the test file after the test + defer os.Remove(testFilePath) // Upload the file userId := uuid.New().String() - blobs, err := azureTest.Connector.Upload([]string{azureTest.TestFilePath}, userId) + filePaths := []string{testFilePath} + blobs, err := abc.Upload(filePaths, userId) require.NoError(t, err) // Download the uploaded file blob := blobs[0] - downloadedData, err := azureTest.Connector.Download(blob.ID, blob.Name) + downloadedData, err := abc.Download(blob.ID, blob.Name) require.NoError(t, err) // Assert that the downloaded content matches the original content - assert.Equal(t, azureTest.TestFileContent, downloadedData) + assert.Equal(t, testFileContent, downloadedData) - // Clean up the test file and blob - azureTest.removeTestFile(t) - err = azureTest.Connector.Delete(blob.ID, blob.Name) + // Delete the uploaded blob + err = abc.Delete(blob.ID, blob.Name) require.NoError(t, err) } -// TestDelete tests the Delete method of AzureBlobConnector -func TestDelete(t *testing.T) { - // Initialize test struct - azureTest := NewAzureBlobTest(t) +// TestAzureBlobConnector_Delete tests the Delete method of AzureBlobConnector +func TestAzureBlobConnector_Delete(t *testing.T) { + // Prepare environment and initialize the connector + connectionString := "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" + containerName := "testblobs" + abc, err := connector.NewAzureBlobConnector(connectionString, containerName) + require.NoError(t, err) + + // Prepare test file content + testFilePath := "testfile.pem" + testFileContent := []byte("This is a test file content.") - // Prepare test file - azureTest.createTestFile(t) + // Create test file + err = os.WriteFile(testFilePath, testFileContent, 0644) + require.NoError(t, err) + + // Clean up the test file after the test + defer os.Remove(testFilePath) // Upload the file userId := uuid.New().String() - blobs, err := azureTest.Connector.Upload([]string{azureTest.TestFilePath}, userId) + filePaths := []string{testFilePath} + blobs, err := abc.Upload(filePaths, userId) require.NoError(t, err) // Get the uploaded blob ID blob := blobs[0] // Now delete the uploaded blob by ID - err = azureTest.Connector.Delete(blob.ID, blob.Name) + err = abc.Delete(blob.ID, blob.Name) require.NoError(t, err) // Try downloading the blob to ensure it was deleted (should fail) - _, err = azureTest.Connector.Download(blob.ID, blob.Name) + _, err = abc.Download(blob.ID, blob.Name) assert.Error(t, err) - - // Clean up the test file - azureTest.removeTestFile(t) } diff --git a/test/integration/infrastructure/connector/az_vault_connector_test.go b/test/integration/infrastructure/connector/az_vault_connector_test.go index c587713..ff06df9 100644 --- a/test/integration/infrastructure/connector/az_vault_connector_test.go +++ b/test/integration/infrastructure/connector/az_vault_connector_test.go @@ -1,134 +1,123 @@ package connector import ( - "crypto_vault_service/internal/infrastructure/connector" "os" "testing" "time" + "crypto_vault_service/internal/infrastructure/connector" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -// Define a struct for the test context to reuse across multiple tests -type AzureVaultTest struct { - Connector *connector.AzureVaultConnector - TestFilePath string - TestFileContent []byte - ContainerName string - ConnectionString string -} - -// Helper function to create a test file -func (abt *AzureVaultTest) createTestFile(t *testing.T) { - err := os.WriteFile(abt.TestFilePath, abt.TestFileContent, 0644) - require.NoError(t, err) -} - -// Helper function to remove the test file -func (abt *AzureVaultTest) removeTestFile(t *testing.T) { - err := os.Remove(abt.TestFilePath) - require.NoError(t, err) -} - -// Helper function to create a new AzureVaultTest instance -func NewAzureVaultTest(t *testing.T) *AzureVaultTest { +// TestUpload tests the Upload method of AzureVaultConnector +func TestAzureVaultConnector_Upload(t *testing.T) { + // Prepare environment and initialize the connector connectionString := "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" containerName := "testblobs" - // Create the Azure Vault Connector abc, err := connector.NewAzureVaultConnector(connectionString, containerName) require.NoError(t, err) - return &AzureVaultTest{ - Connector: abc, - TestFilePath: "testfile.txt", - TestFileContent: []byte("This is a test file content."), - ContainerName: containerName, - ConnectionString: connectionString, - } -} + // Prepare test file content + testFilePath := "testfile.txt" + testFileContent := []byte("This is a test file content.") -// TestUpload tests the Upload method of AzureVaultConnector -func TestAzureVaultConnector_Upload(t *testing.T) { - // Initialize test struct - azureTest := NewAzureVaultTest(t) + // Create test file + err = os.WriteFile(testFilePath, testFileContent, 0644) + require.NoError(t, err) - // Prepare test file - azureTest.createTestFile(t) + // Clean up the test file after the test + defer os.Remove(testFilePath) // Upload the file userId := uuid.New().String() - uploadedKeys, err := azureTest.Connector.Upload([]string{azureTest.TestFilePath}, userId) + keyAlgorithm := "RSA" + keyType := "private" + cryptoKeyMeta, err := abc.Upload(testFilePath, userId, keyType, keyAlgorithm) require.NoError(t, err) // Assert that we received key metadata - require.Len(t, uploadedKeys, 1) - keyMeta := uploadedKeys[0] - assert.NotEmpty(t, keyMeta.ID) - assert.Equal(t, "testfile.txt", keyMeta.Type) // Type based on file name - assert.Equal(t, userId, keyMeta.UserID) - assert.WithinDuration(t, time.Now(), keyMeta.DateTimeCreated, time.Second) - - // Clean up the test file and delete the uploaded key - azureTest.removeTestFile(t) - err = azureTest.Connector.Delete(keyMeta.ID, keyMeta.Type) + assert.NotEmpty(t, cryptoKeyMeta.ID) + assert.Equal(t, keyType, cryptoKeyMeta.Type) + assert.Equal(t, userId, cryptoKeyMeta.UserID) + assert.WithinDuration(t, time.Now(), cryptoKeyMeta.DateTimeCreated, time.Second) + + // Delete the uploaded key + err = abc.Delete(cryptoKeyMeta.ID, cryptoKeyMeta.Type) require.NoError(t, err) } // TestDownload tests the Download method of AzureVaultConnector func TestAzureVaultConnector_Download(t *testing.T) { - // Initialize test struct - azureTest := NewAzureVaultTest(t) + // Prepare environment and initialize the connector + connectionString := "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" + containerName := "testblobs" + abc, err := connector.NewAzureVaultConnector(connectionString, containerName) + require.NoError(t, err) - // Prepare test file - azureTest.createTestFile(t) + // Prepare test file content + testFilePath := "testfile.pem" + testFileContent := []byte("This is a test file content.") + + // Create test file + err = os.WriteFile(testFilePath, testFileContent, 0644) + require.NoError(t, err) + + // Clean up the test file after the test + defer os.Remove(testFilePath) // Upload the file userId := uuid.New().String() - uploadedKeys, err := azureTest.Connector.Upload([]string{azureTest.TestFilePath}, userId) + keyAlgorithm := "RSA" + keyType := "private" + cryptoKeyMeta, err := abc.Upload(testFilePath, userId, keyType, keyAlgorithm) require.NoError(t, err) - // Get the metadata of the uploaded file - keyMeta := uploadedKeys[0] - // Download the uploaded file - downloadedData, err := azureTest.Connector.Download(keyMeta.ID, keyMeta.Type) + downloadedData, err := abc.Download(cryptoKeyMeta.ID, cryptoKeyMeta.Type) require.NoError(t, err) // Assert that the downloaded content matches the original content - assert.Equal(t, azureTest.TestFileContent, downloadedData) + assert.Equal(t, testFileContent, downloadedData) - // Clean up the test file and delete the uploaded key - azureTest.removeTestFile(t) - err = azureTest.Connector.Delete(keyMeta.ID, keyMeta.Type) + // Delete the uploaded key + err = abc.Delete(cryptoKeyMeta.ID, cryptoKeyMeta.Type) require.NoError(t, err) } // TestDelete tests the Delete method of AzureVaultConnector func TestAzureVaultConnector_Delete(t *testing.T) { - // Initialize test struct - azureTest := NewAzureVaultTest(t) + // Prepare environment and initialize the connector + connectionString := "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" + containerName := "testblobs" + abc, err := connector.NewAzureVaultConnector(connectionString, containerName) + require.NoError(t, err) + + // Prepare test file content + testFilePath := "testfile.pem" + testFileContent := []byte("This is a test file content.") - // Prepare test file - azureTest.createTestFile(t) + // Create test file + err = os.WriteFile(testFilePath, testFileContent, 0644) + require.NoError(t, err) + + // Clean up the test file after the test + defer os.Remove(testFilePath) // Upload the file userId := uuid.New().String() - uploadedKeys, err := azureTest.Connector.Upload([]string{azureTest.TestFilePath}, userId) + keyAlgorithm := "RSA" + keyType := "private" + cryptoKeyMeta, err := abc.Upload(testFilePath, userId, keyType, keyAlgorithm) require.NoError(t, err) - // Get the metadata of the uploaded file - keyMeta := uploadedKeys[0] - // Now delete the uploaded key by ID - err = azureTest.Connector.Delete(keyMeta.ID, keyMeta.Type) + err = abc.Delete(cryptoKeyMeta.ID, cryptoKeyMeta.Type) require.NoError(t, err) // Try downloading the key to ensure it was deleted (should fail) - _, err = azureTest.Connector.Download(keyMeta.ID, keyMeta.Type) + _, err = abc.Download(cryptoKeyMeta.ID, cryptoKeyMeta.Type) assert.Error(t, err) - - // Clean up the test file (key is already deleted) - azureTest.removeTestFile(t) } diff --git a/test/integration/persistence/repository/psql_blob_repository_test.go b/test/integration/persistence/repository/psql_blob_repository_test.go index 5d90cd6..3b1b65e 100644 --- a/test/integration/persistence/repository/psql_blob_repository_test.go +++ b/test/integration/persistence/repository/psql_blob_repository_test.go @@ -1,50 +1,47 @@ +// repository/blobrepository_test.go package repository import ( "crypto_vault_service/internal/domain/blobs" "crypto_vault_service/internal/domain/keys" - "fmt" - "os" + "crypto_vault_service/test/helpers" + "testing" "time" "github.com/google/uuid" "github.com/stretchr/testify/assert" - "gorm.io/gorm" ) -// TestBlobPsqlRepository_Create tests the Create method of GormBlobRepository func TestBlobPsqlRepository_Create(t *testing.T) { - err := os.Setenv("DB_TYPE", "postgres") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) + ctx := helpers.SetupTestDB(t) + dbType := "postgres" + defer helpers.TeardownTestDB(t, ctx, dbType) // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - DateTimeCreated: time.Now(), // Valid DateTimeCreated time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), + Type: "public", + Algorithm: "EC", + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), } - // Create a test Blob object with valid UUIDs and required fields + // Create a test Blob object blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID + ID: uuid.New().String(), DateTimeCreated: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID + UserID: cryptographicKey.UserID, Name: "test-blob", Size: 1024, Type: "text", - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + CryptoKey: cryptographicKey, + KeyID: cryptographicKey.ID, } // Call the Create method - err = ctx.BlobRepo.Create(blob) + err := ctx.BlobRepo.Create(blob) assert.NoError(t, err, "Create should not return an error") // Verify the blob is created and exists in DB @@ -55,39 +52,35 @@ func TestBlobPsqlRepository_Create(t *testing.T) { assert.Equal(t, blob.Name, createdBlob.Name, "Name should match") } -// TestBlobPsqlRepository_GetById tests the GetById method of GormBlobRepository func TestBlobPsqlRepository_GetById(t *testing.T) { - err := os.Setenv("DB_TYPE", "postgres") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) + ctx := helpers.SetupTestDB(t) + dbType := "postgres" + defer helpers.TeardownTestDB(t, ctx, dbType) // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - DateTimeCreated: time.Now(), // Valid DateTimeCreated time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), + Type: "public", + Algorithm: "EC", + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), } - // Create a test Blob object with valid UUIDs and required fields + // Create a test Blob object blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID + ID: uuid.New().String(), DateTimeCreated: time.Now(), - UserID: cryptographicKey.UserID, // Link to valid UserID from CryptoKey + UserID: cryptographicKey.UserID, Name: "test-blob", Size: 1024, Type: "text", - - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + CryptoKey: cryptographicKey, + KeyID: cryptographicKey.ID, } // Create the blob in DB - err = ctx.BlobRepo.Create(blob) + err := ctx.BlobRepo.Create(blob) assert.NoError(t, err, "Create should not return an error") // Get the blob by ID @@ -96,92 +89,3 @@ func TestBlobPsqlRepository_GetById(t *testing.T) { assert.NotNil(t, fetchedBlob, "Fetched blob should not be nil") assert.Equal(t, blob.ID, fetchedBlob.ID, "ID should match") } - -// TestBlobPsqlRepository_UpdateById tests the UpdateById method of GormBlobRepository -func TestBlobPsqlRepository_UpdateById(t *testing.T) { - err := os.Setenv("DB_TYPE", "postgres") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } - // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) - - // Create a valid CryptoKey object - cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - DateTimeCreated: time.Now(), // Valid DateTimeCreated time - UserID: uuid.New().String(), // Generate valid UUID for UserID - } - - // Create a test Blob object with valid UUIDs and required fields - blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - DateTimeCreated: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set - } - - // Create the blob in DB - err = ctx.BlobRepo.Create(blob) - assert.NoError(t, err) - - // Update the blob's name - blob.Name = "updated-blob-name" - err = ctx.BlobRepo.UpdateById(blob) - assert.NoError(t, err) - - // Verify the blob is updated - var updatedBlob blobs.BlobMeta - err = ctx.DB.First(&updatedBlob, "id = ?", blob.ID).Error - assert.NoError(t, err) - assert.Equal(t, "updated-blob-name", updatedBlob.Name, "Name should be updated") -} - -// TestBlobPsqlRepository_DeleteById tests the DeleteById method of GormBlobRepository -func TestBlobPsqlRepository_DeleteById(t *testing.T) { - // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) - - // Create a valid CryptoKey object - cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - DateTimeCreated: time.Now(), // Valid DateTimeCreated time - UserID: uuid.New().String(), // Generate valid UUID for UserID - } - - // Create a test Blob object with valid UUIDs and required fields - blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - DateTimeCreated: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set - } - - // Create the blob in DB - err := ctx.BlobRepo.Create(blob) - assert.NoError(t, err) - - // Delete the blob - err = ctx.BlobRepo.DeleteById(blob.ID) - assert.NoError(t, err) - - // Verify the blob is deleted - var deletedBlob blobs.BlobMeta - err = ctx.DB.First(&deletedBlob, "id = ?", blob.ID).Error - assert.Error(t, err, "Blob should be deleted") - assert.Equal(t, gorm.ErrRecordNotFound, err, "Error should be 'record not found'") -} diff --git a/test/integration/persistence/repository/sqlite_blob_repository_test.go b/test/integration/persistence/repository/sqlite_blob_repository_test.go index f8a8ebd..a09731c 100644 --- a/test/integration/persistence/repository/sqlite_blob_repository_test.go +++ b/test/integration/persistence/repository/sqlite_blob_repository_test.go @@ -1,50 +1,47 @@ +// repository/blobrepository_test.go package repository import ( "crypto_vault_service/internal/domain/blobs" "crypto_vault_service/internal/domain/keys" - "fmt" - "os" + "crypto_vault_service/test/helpers" + "testing" "time" "github.com/google/uuid" "github.com/stretchr/testify/assert" - "gorm.io/gorm" ) -// TestBlobInSqliteRepository_Create tests the Create method of GormBlobRepository -func TestBlobInSqliteRepository_Create(t *testing.T) { - err := os.Setenv("DB_TYPE", "sqlite") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } +func TestBlobSqliteRepository_Create(t *testing.T) { // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - DateTimeCreated: time.Now(), // Valid DateTimeCreated time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), + Type: "public", + Algorithm: "EC", + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), } - // Create a test Blob object with valid UUIDs and required fields + // Create a test Blob object blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID + ID: uuid.New().String(), DateTimeCreated: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID + UserID: cryptographicKey.UserID, Name: "test-blob", Size: 1024, Type: "text", - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + CryptoKey: cryptographicKey, + KeyID: cryptographicKey.ID, } // Call the Create method - err = ctx.BlobRepo.Create(blob) + err := ctx.BlobRepo.Create(blob) assert.NoError(t, err, "Create should not return an error") // Verify the blob is created and exists in DB @@ -55,38 +52,35 @@ func TestBlobInSqliteRepository_Create(t *testing.T) { assert.Equal(t, blob.Name, createdBlob.Name, "Name should match") } -// TestBlobInSqliteRepository_GetById tests the GetById method of GormBlobRepository -func TestBlobInSqliteRepository_GetById(t *testing.T) { - err := os.Setenv("DB_TYPE", "sqlite") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } +func TestBlobSqliteRepository_GetById(t *testing.T) { // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) // Create a valid CryptoKey object cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - DateTimeCreated: time.Now(), // Valid DateTimeCreated time - UserID: uuid.New().String(), // Generate valid UUID for UserID + ID: uuid.New().String(), + Type: "public", + Algorithm: "EC", + DateTimeCreated: time.Now(), + UserID: uuid.New().String(), } - // Create a test Blob object with valid UUIDs and required fields + // Create a test Blob object blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID + ID: uuid.New().String(), DateTimeCreated: time.Now(), - UserID: cryptographicKey.UserID, // Link to valid UserID from CryptoKey + UserID: cryptographicKey.UserID, Name: "test-blob", Size: 1024, Type: "text", - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set + CryptoKey: cryptographicKey, + KeyID: cryptographicKey.ID, } // Create the blob in DB - err = ctx.BlobRepo.Create(blob) + err := ctx.BlobRepo.Create(blob) assert.NoError(t, err, "Create should not return an error") // Get the blob by ID @@ -95,94 +89,3 @@ func TestBlobInSqliteRepository_GetById(t *testing.T) { assert.NotNil(t, fetchedBlob, "Fetched blob should not be nil") assert.Equal(t, blob.ID, fetchedBlob.ID, "ID should match") } - -// TestBlobInSqliteRepository_UpdateById tests the UpdateById method of GormBlobRepository -func TestBlobInSqliteRepository_UpdateById(t *testing.T) { - err := os.Setenv("DB_TYPE", "sqlite") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } - // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) - - // Create a valid CryptoKey object - cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - DateTimeCreated: time.Now(), // Valid DateTimeCreated time - UserID: uuid.New().String(), // Generate valid UUID for UserID - } - - // Create a test Blob object with valid UUIDs and required fields - blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - DateTimeCreated: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set - } - - // Create the blob in DB - err = ctx.BlobRepo.Create(blob) - assert.NoError(t, err) - - // Update the blob's name - blob.Name = "updated-blob-name" - err = ctx.BlobRepo.UpdateById(blob) - assert.NoError(t, err) - - // Verify the blob is updated - var updatedBlob blobs.BlobMeta - err = ctx.DB.First(&updatedBlob, "id = ?", blob.ID).Error - assert.NoError(t, err) - assert.Equal(t, "updated-blob-name", updatedBlob.Name, "Name should be updated") -} - -// TestBlobInSqliteRepository_DeleteById tests the DeleteById method of GormBlobRepository -func TestBlobInSqliteRepository_DeleteById(t *testing.T) { - err := os.Setenv("DB_TYPE", "sqlite") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } - // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) - - // Create a valid CryptoKey object - cryptographicKey := keys.CryptoKeyMeta{ - ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type - DateTimeCreated: time.Now(), // Valid DateTimeCreated time - UserID: uuid.New().String(), // Generate valid UUID for UserID - } - - // Create a test Blob object with valid UUIDs and required fields - blob := &blobs.BlobMeta{ - ID: uuid.New().String(), // Generate valid UUID - DateTimeCreated: time.Now(), - UserID: uuid.New().String(), // Generate valid UUID for UserID - Name: "test-blob", - Size: 1024, - Type: "text", - CryptoKey: cryptographicKey, // Set the CryptoKey - KeyID: cryptographicKey.ID, // Ensure ID is set - } - - // Create the blob in DB - err = ctx.BlobRepo.Create(blob) - assert.NoError(t, err) - - // Delete the blob - err = ctx.BlobRepo.DeleteById(blob.ID) - assert.NoError(t, err) - - // Verify the blob is deleted - var deletedBlob blobs.BlobMeta - err = ctx.DB.First(&deletedBlob, "id = ?", blob.ID).Error - assert.Error(t, err, "Blob should be deleted") - assert.Equal(t, gorm.ErrRecordNotFound, err, "Error should be 'record not found'") -} diff --git a/test/integration/persistence/repository/sqlite_key_repository_test.go b/test/integration/persistence/repository/sqlite_key_repository_test.go index ce38524..e0de2cc 100644 --- a/test/integration/persistence/repository/sqlite_key_repository_test.go +++ b/test/integration/persistence/repository/sqlite_key_repository_test.go @@ -2,8 +2,8 @@ package repository import ( "crypto_vault_service/internal/domain/keys" - "fmt" - "os" + "crypto_vault_service/test/helpers" + "testing" "time" @@ -14,122 +14,118 @@ import ( // TestCryptoKeySqliteRepository_Create tests the Create method of GormCryptoKeyRepository func TestCryptoKeySqliteRepository_Create(t *testing.T) { - err := os.Setenv("DB_TYPE", "sqlite") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) // Create a valid CryptoKey object - cryptographicKey := &keys.CryptoKeyMeta{ + cryptoKeyMeta := &keys.CryptoKeyMeta{ ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type + Type: "public", // Example key type + Algorithm: "EC", // Example algorithm DateTimeCreated: time.Now(), // Valid DateTimeCreated time UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB - err = ctx.CryptoKeyRepo.Create(cryptographicKey) + err := ctx.CryptoKeyRepo.Create(cryptoKeyMeta) assert.NoError(t, err, "Create should not return an error") // Verify the cryptographic key is created and exists in DB - var createdKey keys.CryptoKeyMeta - err = ctx.DB.First(&createdKey, "id = ?", cryptographicKey.ID).Error + var createdCryptKeyMeta keys.CryptoKeyMeta + err = ctx.DB.First(&createdCryptKeyMeta, "id = ?", cryptoKeyMeta.ID).Error assert.NoError(t, err, "Failed to find created cryptographic key") - assert.Equal(t, cryptographicKey.ID, createdKey.ID, "ID should match") - assert.Equal(t, cryptographicKey.Type, createdKey.Type, "Type should match") + assert.Equal(t, cryptoKeyMeta.ID, createdCryptKeyMeta.ID, "ID should match") + assert.Equal(t, cryptoKeyMeta.Type, createdCryptKeyMeta.Type, "Type should match") } // TestCryptoKeySqliteRepository_GetByID tests the GetByID method of GormCryptoKeyRepository func TestCryptoKeySqliteRepository_GetByID(t *testing.T) { - err := os.Setenv("DB_TYPE", "sqlite") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) // Create a valid CryptoKey object - cryptographicKey := &keys.CryptoKeyMeta{ + cryptoKeyMeta := &keys.CryptoKeyMeta{ ID: uuid.New().String(), // Generate valid UUID for ID - Type: "RSA", // Example key type + Type: "private", // Example key type + Algorithm: "RSA", // Example algorithm DateTimeCreated: time.Now(), // Valid DateTimeCreated time UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB - err = ctx.CryptoKeyRepo.Create(cryptographicKey) + err := ctx.CryptoKeyRepo.Create(cryptoKeyMeta) assert.NoError(t, err, "Create should not return an error") // Get the cryptographic key by ID - fetchedKey, err := ctx.CryptoKeyRepo.GetByID(cryptographicKey.ID) + fetchedCryptoKeyMeta, err := ctx.CryptoKeyRepo.GetByID(cryptoKeyMeta.ID) assert.NoError(t, err, "GetByID should not return an error") - assert.NotNil(t, fetchedKey, "Fetched cryptographic key should not be nil") - assert.Equal(t, cryptographicKey.ID, fetchedKey.ID, "ID should match") + assert.NotNil(t, fetchedCryptoKeyMeta, "Fetched cryptographic key should not be nil") + assert.Equal(t, cryptoKeyMeta.ID, fetchedCryptoKeyMeta.ID, "ID should match") } // TestCryptoKeySqliteRepository_UpdateByID tests the UpdateByID method of GormCryptoKeyRepository func TestCryptoKeySqliteRepository_UpdateByID(t *testing.T) { - err := os.Setenv("DB_TYPE", "sqlite") - if err != nil { - fmt.Println("Error setting environment variable:", err) - } // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) // Create a valid CryptoKey object - cryptographicKey := &keys.CryptoKeyMeta{ + cryptoKeyMeta := &keys.CryptoKeyMeta{ ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type + Type: "public", // Example key type + Algorithm: "EC", // Example algorithm DateTimeCreated: time.Now(), // Valid DateTimeCreated time UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB - err = ctx.CryptoKeyRepo.Create(cryptographicKey) + err := ctx.CryptoKeyRepo.Create(cryptoKeyMeta) assert.NoError(t, err, "Create should not return an error") // Update the cryptographic key's type - cryptographicKey.Type = "ECDSA" - err = ctx.CryptoKeyRepo.UpdateByID(cryptographicKey) + cryptoKeyMeta.Type = "public" + err = ctx.CryptoKeyRepo.UpdateByID(cryptoKeyMeta) assert.NoError(t, err, "UpdateByID should not return an error") // Verify the cryptographic key is updated - var updatedKey keys.CryptoKeyMeta - err = ctx.DB.First(&updatedKey, "id = ?", cryptographicKey.ID).Error + var updatedCryptoKeyMeta keys.CryptoKeyMeta + err = ctx.DB.First(&updatedCryptoKeyMeta, "id = ?", cryptoKeyMeta.ID).Error assert.NoError(t, err, "Failed to find updated cryptographic key") - assert.Equal(t, "ECDSA", updatedKey.Type, "Type should be updated") + assert.Equal(t, cryptoKeyMeta.Type, updatedCryptoKeyMeta.Type, "Type should be updated") } // TestCryptoKeySqliteRepository_DeleteByID tests the DeleteByID method of GormCryptoKeyRepository func TestCryptoKeySqliteRepository_DeleteByID(t *testing.T) { // Set up test context - ctx := setupTestDB(t) - defer teardownTestDB(t, ctx) + ctx := helpers.SetupTestDB(t) + dbType := "sqlite" + defer helpers.TeardownTestDB(t, ctx, dbType) // Create a valid CryptoKey object - cryptographicKey := &keys.CryptoKeyMeta{ + cryptoKeyMeta := &keys.CryptoKeyMeta{ ID: uuid.New().String(), // Generate valid UUID for ID - Type: "AES", // Example key type + Type: "public", // Example key type + Algorithm: "EC", // Example algorithm DateTimeCreated: time.Now(), // Valid DateTimeCreated time UserID: uuid.New().String(), // Generate valid UUID for UserID } // Create the cryptographic key in DB - err := ctx.CryptoKeyRepo.Create(cryptographicKey) + err := ctx.CryptoKeyRepo.Create(cryptoKeyMeta) assert.NoError(t, err, "Create should not return an error") // Delete the cryptographic key by ID - err = ctx.CryptoKeyRepo.DeleteByID(cryptographicKey.ID) + err = ctx.CryptoKeyRepo.DeleteByID(cryptoKeyMeta.ID) assert.NoError(t, err, "DeleteByID should not return an error") // Verify the cryptographic key is deleted - var deletedKey keys.CryptoKeyMeta - err = ctx.DB.First(&deletedKey, "id = ?", cryptographicKey.ID).Error + var deletedCryptoKeyMeta keys.CryptoKeyMeta + err = ctx.DB.First(&deletedCryptoKeyMeta, "id = ?", cryptoKeyMeta.ID).Error assert.Error(t, err, "Cryptographic key should be deleted") assert.Equal(t, gorm.ErrRecordNotFound, err, "Error should be 'record not found'") } diff --git a/test/integration/persistence/repository/test_repository_context.go b/test/integration/persistence/repository/test_repository_context.go deleted file mode 100644 index c014a74..0000000 --- a/test/integration/persistence/repository/test_repository_context.go +++ /dev/null @@ -1,126 +0,0 @@ -package repository - -import ( - "crypto_vault_service/internal/domain/blobs" - "crypto_vault_service/internal/domain/keys" - "crypto_vault_service/internal/persistence/repository" - "fmt" - "os" - "testing" - - "gorm.io/driver/postgres" - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -// TestRepositoryContext struct to hold DB and repositories for each test -type TestRepositoryContext struct { - DB *gorm.DB - BlobRepo *repository.GormBlobRepository - CryptoKeyRepo *repository.GormCryptoKeyRepository -} - -// Setup function to initialize the test DB and repositories -func setupTestDB(t *testing.T) *TestRepositoryContext { - var err error - var db *gorm.DB - - // Check for the DB type to use (SQLite in-memory or PostgreSQL) - dbType := os.Getenv("DB_TYPE") - if dbType == "" { - // Default to SQLite in-memory if DB_TYPE is not set - dbType = "sqlite" - } - - switch dbType { - case "postgres": - // Setup PostgreSQL connection - dsn := "user=postgres password=postgres host=localhost port=5432 sslmode=disable" - if dsn == "" { - t.Fatalf("POSTGRES_DSN environment variable is not set") - } - - db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) - if err != nil { - t.Fatalf("Failed to connect to PostgreSQL: %v", err) - } - - // Check if the `blobs` database exists - sqlDB, err := db.DB() - if err != nil { - t.Fatalf("Failed to get raw DB connection: %v", err) - } - - // Query to check if the `blobs` database exists - var dbExists bool - err = sqlDB.QueryRow("SELECT 1 FROM pg_database WHERE datname = 'blobs'").Scan(&dbExists) - if err != nil { - if err.Error() != "sql: no rows in result set" { - t.Fatalf("Failed to check if database exists: %v", err) - } - // The database does not exist, create it - _, err = sqlDB.Exec("CREATE DATABASE blobs") - if err != nil { - t.Fatalf("Failed to create database: %v", err) - } - fmt.Println("Database 'blobs' created successfully.") - } - - // Now, open a connection to the `blobs` database - dsn = "user=postgres password=postgres host=localhost port=5432 dbname=blobs sslmode=disable" - db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) - if err != nil { - t.Fatalf("Failed to connect to PostgreSQL database 'blobs': %v", err) - } - - case "sqlite": - // Setup SQLite in-memory connection - db, err = gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) - if err != nil { - t.Fatalf("Failed to connect to SQLite: %v", err) - } - - default: - t.Fatalf("Unsupported DB_TYPE value: %s", dbType) - } - - // Migrate the schema for Blob and CryptoKey - err = db.AutoMigrate(&blobs.BlobMeta{}, &keys.CryptoKeyMeta{}) - if err != nil { - t.Fatalf("Failed to migrate schema: %v", err) - } - - // Initialize the repositories with the DB instance - blobRepo := &repository.GormBlobRepository{DB: db} - cryptoKeyRepo := &repository.GormCryptoKeyRepository{DB: db} - - // Return the test context that holds the DB and repositories - return &TestRepositoryContext{ - DB: db, - BlobRepo: blobRepo, - CryptoKeyRepo: cryptoKeyRepo, - } -} - -// Teardown function to clean up after tests (optional, for DB cleanup) -func teardownTestDB(t *testing.T, ctx *TestRepositoryContext) { - sqlDB, err := ctx.DB.DB() - if err != nil { - t.Fatalf("Failed to get DB connection: %v", err) - } - sqlDB.Close() -} - -// TestMain setup and teardown for the entire test suite -func TestMain(m *testing.M) { - // Set up test context - ctx := setupTestDB(nil) - // Run tests - code := m.Run() - // Clean up after tests - teardownTestDB(nil, ctx) - // Exit with the test result code - if code != 0 { - fmt.Println("Tests failed.") - } -} diff --git a/test/unit/app/services/blob_services_mock_test.go b/test/unit/app/services/blob_services_mock_test.go index 8cc9f8a..464f6e8 100644 --- a/test/unit/app/services/blob_services_mock_test.go +++ b/test/unit/app/services/blob_services_mock_test.go @@ -3,6 +3,8 @@ package services import ( "crypto_vault_service/internal/app/services" "crypto_vault_service/internal/domain/blobs" + "crypto_vault_service/test/helpers" + "fmt" "testing" @@ -12,8 +14,8 @@ import ( func TestBlobUploadService_Upload(t *testing.T) { // Prepare mock dependencies - mockBlobConnector := new(MockBlobConnector) - mockBlobRepository := new(MockBlobRepository) + mockBlobConnector := new(helpers.MockBlobConnector) + mockBlobRepository := new(helpers.MockBlobRepository) // Initialize the service with mock dependencies service := services.NewBlobUploadService(mockBlobConnector, mockBlobRepository) @@ -73,8 +75,8 @@ func TestBlobUploadService_Upload(t *testing.T) { func TestBlobMetadataService(t *testing.T) { // Prepare mock dependencies - mockBlobConnector := new(MockBlobConnector) - mockBlobRepository := new(MockBlobRepository) + mockBlobConnector := new(helpers.MockBlobConnector) + mockBlobRepository := new(helpers.MockBlobRepository) // Initialize the service with mock dependencies metadataService := services.NewBlobMetadataService(mockBlobRepository, mockBlobConnector) @@ -104,7 +106,7 @@ func TestBlobMetadataService(t *testing.T) { func TestBlobDownloadService(t *testing.T) { // Prepare mock dependencies - mockBlobConnector := new(MockBlobConnector) + mockBlobConnector := new(helpers.MockBlobConnector) // Initialize the service with mock dependencies downloadService := services.NewBlobDownloadService(mockBlobConnector) diff --git a/test/unit/domain/blobs/model_test.go b/test/unit/domain/blobs/model_test.go index 137e413..a7d5271 100644 --- a/test/unit/domain/blobs/model_test.go +++ b/test/unit/domain/blobs/model_test.go @@ -30,7 +30,7 @@ func NewBlobValidationTests() *BlobValidationTests { Type: "text", EncryptionAlgorithm: "AES", HashAlgorithm: "SHA256", - CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, + CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Algorithm: "AES", Type: "private", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } @@ -43,7 +43,7 @@ func NewBlobValidationTests() *BlobValidationTests { Type: "text", EncryptionAlgorithm: "AES", HashAlgorithm: "SHA256", - CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, + CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Algorithm: "AES", Type: "private", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } @@ -56,7 +56,7 @@ func NewBlobValidationTests() *BlobValidationTests { Type: "text", EncryptionAlgorithm: "AES", HashAlgorithm: "SHA256", - CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Type: "AES", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, + CryptoKey: keys.CryptoKeyMeta{ID: uuid.New().String(), Algorithm: "AES", Type: "private", DateTimeCreated: time.Now(), UserID: uuid.New().String()}, KeyID: uuid.New().String(), } diff --git a/test/unit/domain/keys/model_test.go b/test/unit/domain/keys/model_test.go index aa69695..66f6943 100644 --- a/test/unit/domain/keys/model_test.go +++ b/test/unit/domain/keys/model_test.go @@ -14,7 +14,8 @@ func TestCryptoKeyValidation(t *testing.T) { // Valid CryptoKey validKey := keys.CryptoKeyMeta{ ID: uuid.New().String(), // Valid UUID - Type: "AES", // Valid Type + Type: "symmetric", // Valid Type + Algorithm: "AES", // Valid Algorithm DateTimeCreated: time.Now(), UserID: uuid.New().String(), // Valid UserID } @@ -43,7 +44,8 @@ func TestCryptoKeyValidations(t *testing.T) { // Test missing UserID (should fail) invalidKey := keys.CryptoKeyMeta{ ID: uuid.New().String(), // Valid UUID - Type: "AES", // Valid Type + Type: "symmetric", // Valid Type + Algorithm: "AES", // Valid Algorithm DateTimeCreated: time.Now(), UserID: "", // Invalid empty UserID } diff --git a/test/unit/infrastructure/cryptography/aes_test.go b/test/unit/infrastructure/cryptography/aes_test.go index 6f753f3..c657e5b 100644 --- a/test/unit/infrastructure/cryptography/aes_test.go +++ b/test/unit/infrastructure/cryptography/aes_test.go @@ -10,33 +10,33 @@ import ( // AES struct to encapsulate AES-related test cases type AESTests struct { - AESCrypto *cryptography.AESCrypto + AES *cryptography.AES } // NewAESTests is a constructor that creates a new instance of AESTests func NewAESTests() *AESTests { return &AESTests{ - AESCrypto: &cryptography.AESCrypto{}, + AES: &cryptography.AES{}, } } // TestEncryptDecrypt tests the encryption and decryption functionality func (at *AESTests) TestEncryptDecrypt(t *testing.T) { // Generate a random key of 16 bytes (128-bit AES) - key, err := at.AESCrypto.GenerateKey(16) + key, err := at.AES.GenerateKey(16) assert.NoError(t, err) // Define a plaintext to encrypt and decrypt plainText := []byte("This is a test message.") // Encrypt the plaintext - ciphertext, err := at.AESCrypto.Encrypt(plainText, key) + ciphertext, err := at.AES.Encrypt(plainText, key) assert.NoError(t, err) assert.NotNil(t, ciphertext) assert.Greater(t, len(ciphertext), 0, "Ciphertext should be longer than 0") // Decrypt the ciphertext - decryptedText, err := at.AESCrypto.Decrypt(ciphertext, key) + decryptedText, err := at.AES.Decrypt(ciphertext, key) assert.NoError(t, err) assert.NotNil(t, decryptedText) @@ -51,19 +51,19 @@ func (at *AESTests) TestEncryptionWithInvalidKey(t *testing.T) { plainText := []byte("This is a test.") // Try encrypting with an invalid key - _, err := at.AESCrypto.Encrypt(plainText, key) + _, err := at.AES.Encrypt(plainText, key) assert.Error(t, err) } // TestGenerateKey tests key generation functionality func (at *AESTests) TestGenerateKey(t *testing.T) { // Generate a random AES key with 16 bytes (128-bit AES) - key, err := at.AESCrypto.GenerateKey(16) + key, err := at.AES.GenerateKey(16) assert.NoError(t, err) assert.Equal(t, len(key), 16) // Try generating a 32-byte AES key (256-bit AES) - key256, err := at.AESCrypto.GenerateKey(32) + key256, err := at.AES.GenerateKey(32) assert.NoError(t, err) assert.Equal(t, len(key256), 32) } @@ -71,31 +71,31 @@ func (at *AESTests) TestGenerateKey(t *testing.T) { // TestDecryptWithWrongKey tests decryption with a wrong key func (at *AESTests) TestDecryptWithWrongKey(t *testing.T) { // Generate a random 16-byte AES key - key, err := at.AESCrypto.GenerateKey(16) + key, err := at.AES.GenerateKey(16) assert.NoError(t, err) // Encrypt the data plainText := []byte("Test decryption with wrong key.") - ciphertext, err := at.AESCrypto.Encrypt(plainText, key) + ciphertext, err := at.AES.Encrypt(plainText, key) assert.NoError(t, err) // Generate a new, different key for decryption - anotherKey, err := at.AESCrypto.GenerateKey(16) + anotherKey, err := at.AES.GenerateKey(16) assert.NoError(t, err) // Try to decrypt with the wrong key - _, err = at.AESCrypto.Decrypt(ciphertext, anotherKey) + _, err = at.AES.Decrypt(ciphertext, anotherKey) assert.Error(t, err, "Decryption with the wrong key should fail") } // TestDecryptShortCiphertext tests the case where the ciphertext is too short func (at *AESTests) TestDecryptShortCiphertext(t *testing.T) { // Generate a random key - key, err := at.AESCrypto.GenerateKey(16) + key, err := at.AES.GenerateKey(16) assert.NoError(t, err) // Attempt to decrypt a too-short ciphertext - _, err = at.AESCrypto.Decrypt([]byte("short"), key) + _, err = at.AES.Decrypt([]byte("short"), key) assert.Error(t, err, "Decrypting a ciphertext that's too short should fail") } diff --git a/test/unit/infrastructure/cryptography/ecdsa_test.go b/test/unit/infrastructure/cryptography/ecdsa_test.go index c020127..6fa2b12 100644 --- a/test/unit/infrastructure/cryptography/ecdsa_test.go +++ b/test/unit/infrastructure/cryptography/ecdsa_test.go @@ -14,13 +14,13 @@ import ( ) type ECDSATests struct { - ecc *cryptography.ECCrypto + ecc *cryptography.EC } // NewECDSATests is a constructor that creates a new instance of ECDSATests func NewECDSATests() *ECDSATests { return &ECDSATests{ - ecc: &cryptography.ECCrypto{}, + ecc: &cryptography.EC{}, } } diff --git a/test/unit/infrastructure/cryptography/rsa_test.go b/test/unit/infrastructure/cryptography/rsa_test.go index c7faac5..07026d1 100644 --- a/test/unit/infrastructure/cryptography/rsa_test.go +++ b/test/unit/infrastructure/cryptography/rsa_test.go @@ -11,20 +11,20 @@ import ( // RSATests struct to encapsulate RSA-related test cases type RSATests struct { - RSACrypto *cryptography.RSACrypto + RSA *cryptography.RSA } // NewRSATests is a constructor that creates a new instance of RSATests func NewRSATests() *RSATests { return &RSATests{ - RSACrypto: &cryptography.RSACrypto{}, + RSA: &cryptography.RSA{}, } } // TestGenerateRSAKeys tests the generation of RSA keys func (rt *RSATests) TestGenerateRSAKeys(t *testing.T) { // Generate RSA keys with 2048-bit size - privateKey, publicKey, err := rt.RSACrypto.GenerateKeys(2048) + privateKey, publicKey, err := rt.RSA.GenerateKeys(2048) assert.NoError(t, err, "Error generating RSA keys") assert.NotNil(t, privateKey, "Private key should not be nil") assert.NotNil(t, publicKey, "Public key should not be nil") @@ -37,18 +37,18 @@ func (rt *RSATests) TestGenerateRSAKeys(t *testing.T) { // TestEncryptDecrypt tests the encryption and decryption methods of RSA func (rt *RSATests) TestEncryptDecrypt(t *testing.T) { // Generate RSA keys - privateKey, publicKey, err := rt.RSACrypto.GenerateKeys(2048) + privateKey, publicKey, err := rt.RSA.GenerateKeys(2048) assert.NoError(t, err) // Message to encrypt plainText := []byte("This is a secret message") // Encrypt the message - encryptedData, err := rt.RSACrypto.Encrypt(plainText, publicKey) + encryptedData, err := rt.RSA.Encrypt(plainText, publicKey) assert.NoError(t, err, "Error encrypting data") // Decrypt the message - decryptedData, err := rt.RSACrypto.Decrypt(encryptedData, privateKey) + decryptedData, err := rt.RSA.Decrypt(encryptedData, privateKey) assert.NoError(t, err, "Error decrypting data") // Ensure the decrypted data matches the original message @@ -58,26 +58,26 @@ func (rt *RSATests) TestEncryptDecrypt(t *testing.T) { // TestSaveAndReadKeys tests saving and reading RSA keys to and from files func (rt *RSATests) TestSaveAndReadKeys(t *testing.T) { // Generate RSA keys - privateKey, publicKey, err := rt.RSACrypto.GenerateKeys(2048) + privateKey, publicKey, err := rt.RSA.GenerateKeys(2048) assert.NoError(t, err) // Save keys to files privateKeyFile := "private.pem" publicKeyFile := "public.pem" - err = rt.RSACrypto.SavePrivateKeyToFile(privateKey, privateKeyFile) + err = rt.RSA.SavePrivateKeyToFile(privateKey, privateKeyFile) assert.NoError(t, err, "Error saving private key to file") - err = rt.RSACrypto.SavePublicKeyToFile(publicKey, publicKeyFile) + err = rt.RSA.SavePublicKeyToFile(publicKey, publicKeyFile) assert.NoError(t, err, "Error saving public key to file") // Read the keys back from the files - readPrivateKey, err := rt.RSACrypto.ReadPrivateKey(privateKeyFile) + readPrivateKey, err := rt.RSA.ReadPrivateKey(privateKeyFile) assert.NoError(t, err, "Error reading private key from file") assert.Equal(t, privateKey.N, readPrivateKey.N, "Private key N component should match") assert.Equal(t, privateKey.E, readPrivateKey.E, "Private key E component should match") - readPublicKey, err := rt.RSACrypto.ReadPublicKey(publicKeyFile) + readPublicKey, err := rt.RSA.ReadPublicKey(publicKeyFile) assert.NoError(t, err, "Error reading public key from file") assert.Equal(t, publicKey.N, readPublicKey.N, "Public key N component should match") assert.Equal(t, publicKey.E, readPublicKey.E, "Public key E component should match") @@ -90,42 +90,42 @@ func (rt *RSATests) TestSaveAndReadKeys(t *testing.T) { // TestEncryptWithInvalidKey tests encryption with an invalid public key func (rt *RSATests) TestEncryptWithInvalidKey(t *testing.T) { // Generate RSA keys - _, _, err := rt.RSACrypto.GenerateKeys(2048) + _, _, err := rt.RSA.GenerateKeys(2048) assert.NoError(t, err) // Attempt to encrypt with a nil public key (invalid case) plainText := []byte("This should fail encryption") - _, err = rt.RSACrypto.Encrypt(plainText, nil) + _, err = rt.RSA.Encrypt(plainText, nil) assert.Error(t, err, "Encryption should fail with an invalid public key") // Attempt to decrypt with a nil private key (invalid case) - _, err = rt.RSACrypto.Decrypt(plainText, nil) + _, err = rt.RSA.Decrypt(plainText, nil) assert.Error(t, err, "Decryption should fail with an invalid private key") // Attempt to decrypt with a different private key (invalid case) - _, err = rt.RSACrypto.Decrypt(plainText, &rsa.PrivateKey{}) + _, err = rt.RSA.Decrypt(plainText, &rsa.PrivateKey{}) assert.Error(t, err, "Decryption should fail with an invalid private key") } // TestSavePrivateKeyInvalidPath tests saving a private key to an invalid path func (rt *RSATests) TestSavePrivateKeyInvalidPath(t *testing.T) { // Generate RSA keys - privateKey, _, err := rt.RSACrypto.GenerateKeys(2048) + privateKey, _, err := rt.RSA.GenerateKeys(2048) assert.NoError(t, err) // Try saving the private key to an invalid file path - err = rt.RSACrypto.SavePrivateKeyToFile(privateKey, "/invalid/path/private.pem") + err = rt.RSA.SavePrivateKeyToFile(privateKey, "/invalid/path/private.pem") assert.Error(t, err, "Saving private key to an invalid path should return an error") } // TestSavePublicKeyInvalidPath tests saving a public key to an invalid path func (rt *RSATests) TestSavePublicKeyInvalidPath(t *testing.T) { // Generate RSA keys - _, publicKey, err := rt.RSACrypto.GenerateKeys(2048) + _, publicKey, err := rt.RSA.GenerateKeys(2048) assert.NoError(t, err) // Try saving the public key to an invalid file path - err = rt.RSACrypto.SavePublicKeyToFile(publicKey, "/invalid/path/public.pem") + err = rt.RSA.SavePublicKeyToFile(publicKey, "/invalid/path/public.pem") assert.Error(t, err, "Saving public key to an invalid path should return an error") }