blob: e11f238a78d5fe486be7bda7f441a806aa266f57 [file]
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package models
import (
"net/http"
"testing"
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
"github.com/stretchr/testify/assert"
)
func TestBitbucketConn_SetupAuthentication_ApiToken(t *testing.T) {
// Test API token authentication
conn := BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "api_token_123",
},
UsesApiToken: true,
}
req, err := http.NewRequest("GET", "https://api.bitbucket.org/2.0/user", nil)
assert.NoError(t, err)
authErr := conn.SetupAuthentication(req)
assert.Nil(t, authErr)
assert.NotEmpty(t, req.Header.Get("Authorization"))
assert.Contains(t, req.Header.Get("Authorization"), "Basic")
}
func TestBitbucketConn_SetupAuthentication_AppPassword(t *testing.T) {
// Test app password authentication
conn := BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "bitbucket_username",
Password: "app_password_123",
},
UsesApiToken: false,
}
req, err := http.NewRequest("GET", "https://api.bitbucket.org/2.0/user", nil)
assert.NoError(t, err)
authErr := conn.SetupAuthentication(req)
assert.Nil(t, authErr)
assert.NotEmpty(t, req.Header.Get("Authorization"))
assert.Contains(t, req.Header.Get("Authorization"), "Basic")
}
func TestBitbucketConn_Sanitize(t *testing.T) {
// Test that Sanitize removes the password
conn := BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "secret_password",
},
UsesApiToken: true,
}
sanitized := conn.Sanitize()
assert.Empty(t, sanitized.Password)
assert.Equal(t, "user@example.com", sanitized.Username)
assert.True(t, sanitized.UsesApiToken)
}
func TestBitbucketConn_UsesApiToken_Default(t *testing.T) {
// Test that UsesApiToken can be set correctly
conn := BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "token",
},
UsesApiToken: true,
}
assert.True(t, conn.UsesApiToken)
// Test app password mode
conn2 := BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "username",
Password: "password",
},
UsesApiToken: false,
}
assert.False(t, conn2.UsesApiToken)
}
func TestBitbucketConnection_Sanitize(t *testing.T) {
// Test that BitbucketConnection.Sanitize works correctly
connection := BitbucketConnection{
BitbucketConn: BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "secret_token",
},
UsesApiToken: true,
},
}
sanitized := connection.Sanitize()
assert.Empty(t, sanitized.Password)
assert.Equal(t, "user@example.com", sanitized.Username)
assert.True(t, sanitized.UsesApiToken)
}
func TestBitbucketConnection_TableName(t *testing.T) {
connection := BitbucketConnection{}
assert.Equal(t, "_tool_bitbucket_connections", connection.TableName())
}
func TestBitbucketConnection_MergeFromRequest_PreservesPassword(t *testing.T) {
original := &BitbucketConnection{
BitbucketConn: BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "secret_token",
},
UsesApiToken: true,
},
}
target := &BitbucketConnection{}
*target = *original // copy
// Update without password (empty password should preserve original)
body := map[string]interface{}{
"username": "new_user@example.com",
"usesApiToken": false,
}
err := original.MergeFromRequest(target, body)
assert.NoError(t, err)
assert.Equal(t, "new_user@example.com", target.Username)
assert.Equal(t, "secret_token", target.Password) // Should preserve
assert.False(t, target.UsesApiToken)
}
func TestBitbucketConnection_MergeFromRequest_UpdatesPassword(t *testing.T) {
original := &BitbucketConnection{
BitbucketConn: BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "old_token",
},
UsesApiToken: true,
},
}
target := &BitbucketConnection{}
*target = *original
// Update with new password
body := map[string]interface{}{
"username": "user@example.com",
"password": "new_token",
"usesApiToken": true,
}
err := original.MergeFromRequest(target, body)
assert.NoError(t, err)
assert.Equal(t, "new_token", target.Password) // Should update
}
func TestBitbucketConnection_MergeFromRequest_TogglesUsesApiToken(t *testing.T) {
original := &BitbucketConnection{
BitbucketConn: BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "credential",
},
UsesApiToken: false, // App password
},
}
target := &BitbucketConnection{}
*target = *original
// Toggle to API token
body := map[string]interface{}{
"usesApiToken": true,
"password": "api_token_123",
}
err := original.MergeFromRequest(target, body)
assert.NoError(t, err)
assert.True(t, target.UsesApiToken)
assert.Equal(t, "api_token_123", target.Password)
}
func TestBitbucketConn_SetupAuthentication_BasicAuthFormat(t *testing.T) {
// Test that BOTH methods produce Basic Auth (not Bearer)
tests := []struct {
name string
username string
password string
usesApiToken bool
}{
{
name: "API Token produces Basic Auth",
username: "user@example.com",
password: "api_token_123",
usesApiToken: true,
},
{
name: "App Password produces Basic Auth",
username: "bitbucket_username",
password: "app_password_123",
usesApiToken: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
conn := BitbucketConn{
BasicAuth: api.BasicAuth{
Username: tt.username,
Password: tt.password,
},
UsesApiToken: tt.usesApiToken,
}
req, _ := http.NewRequest("GET", "https://api.bitbucket.org/2.0/user", nil)
err := conn.SetupAuthentication(req)
assert.Nil(t, err)
authHeader := req.Header.Get("Authorization")
assert.NotEmpty(t, authHeader)
assert.Contains(t, authHeader, "Basic ", "Should use Basic auth, not Bearer")
assert.NotContains(t, authHeader, "Bearer", "Should NOT use Bearer token")
})
}
}
func TestBitbucketConn_EmptyPassword(t *testing.T) {
conn := BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "",
},
UsesApiToken: true,
}
req, _ := http.NewRequest("GET", "https://api.bitbucket.org/2.0/user", nil)
err := conn.SetupAuthentication(req)
// Should still set auth header (though it won't work in practice)
assert.Nil(t, err)
assert.NotEmpty(t, req.Header.Get("Authorization"))
}
func TestBitbucketConn_SpecialCharactersInPassword(t *testing.T) {
conn := BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "p@ssw0rd!#$%&*()+=",
},
UsesApiToken: true,
}
req, _ := http.NewRequest("GET", "https://api.bitbucket.org/2.0/user", nil)
err := conn.SetupAuthentication(req)
assert.Nil(t, err)
assert.NotEmpty(t, req.Header.Get("Authorization"))
}
func TestBitbucketConnection_Sanitize_PreservesUsesApiToken(t *testing.T) {
connection := BitbucketConnection{
BitbucketConn: BitbucketConn{
BasicAuth: api.BasicAuth{
Username: "user@example.com",
Password: "secret",
},
UsesApiToken: true,
},
}
sanitized := connection.Sanitize()
assert.Empty(t, sanitized.Password, "Password should be removed")
assert.Equal(t, "user@example.com", sanitized.Username, "Username should be preserved")
assert.True(t, sanitized.UsesApiToken, "UsesApiToken flag should be preserved")
}