initial public commit

This commit is contained in:
Brad Rydzewski
2014-02-07 03:10:01 -07:00
commit d5e5797934
183 changed files with 15701 additions and 0 deletions

71
pkg/database/builds.go Normal file
View File

@@ -0,0 +1,71 @@
package database
import (
. "github.com/drone/drone/pkg/model"
"github.com/russross/meddler"
)
// Name of the Build table in the database
const buildTable = "builds"
// SQL Queries to retrieve a list of all Commits belonging to a Repo.
const buildStmt = `
SELECT id, commit_id, slug, status, started, finished, duration, created, updated, stdout
FROM builds
WHERE commit_id = ?
ORDER BY slug ASC
`
// SQL Queries to retrieve a Build by id.
const buildFindStmt = `
SELECT id, commit_id, slug, status, started, finished, duration, created, updated, stdout
FROM builds
WHERE id = ?
LIMIT 1
`
// SQL Queries to retrieve a Commit by name and repo id.
const buildFindSlugStmt = `
SELECT id, commit_id, slug, status, started, finished, duration, created, updated, stdout
FROM builds
WHERE slug = ? AND commit_id = ?
LIMIT 1
`
// SQL Queries to delete a Commit.
const buildDeleteStmt = `
DELETE FROM builds WHERE id = ?
`
// Returns the Build with the given ID.
func GetBuild(id int64) (*Build, error) {
build := Build{}
err := meddler.QueryRow(db, &build, buildFindStmt, id)
return &build, err
}
// Returns the Build with the given slug.
func GetBuildSlug(slug string, commit int64) (*Build, error) {
build := Build{}
err := meddler.QueryRow(db, &build, buildFindSlugStmt, slug, commit)
return &build, err
}
// Creates a new Build.
func SaveBuild(build *Build) error {
return meddler.Save(db, buildTable, build)
}
// Deletes an existing Build.
func DeleteBuild(id int64) error {
_, err := db.Exec(buildDeleteStmt, id)
return err
}
// Returns a list of all Builds associated
// with the specified Commit ID and branch.
func ListBuilds(id int64) ([]*Build, error) {
var builds []*Build
err := meddler.QueryAll(db, &builds, buildStmt, id)
return builds, err
}

174
pkg/database/commits.go Normal file
View File

@@ -0,0 +1,174 @@
package database
import (
"time"
. "github.com/drone/drone/pkg/model"
"github.com/russross/meddler"
)
// Name of the Commit table in the database
const commitTable = "commits"
// SQL Queries to retrieve a list of all Commits belonging to a Repo.
const commitStmt = `
SELECT id, repo_id, status, started, finished, duration,
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
FROM commits
WHERE repo_id = ? AND branch = ?
ORDER BY created DESC
LIMIT 10
`
// SQL Queries to retrieve the latest Commit.
const commitLatestStmt = `
SELECT id, repo_id, status, started, finished, duration,
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
FROM commits
WHERE repo_id = ? AND branch = ?
ORDER BY created DESC
LIMIT 1
`
// SQL Queries to retrieve a Commit by id.
const commitFindStmt = `
SELECT id, repo_id, status, started, finished, duration,
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
FROM commits
WHERE id = ?
`
// SQL Queries to retrieve a Commit by name and repo id.
const commitFindHashStmt = `
SELECT id, repo_id, status, started, finished, duration,
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
FROM commits
WHERE hash = ? AND repo_id = ?
LIMIT 1
`
// SQL Query to retrieve a list of recent commits by user.
const userCommitRecentStmt = `
SELECT r.slug, r.host, r.owner, r.name,
c.status, c.started, c.finished, c.duration, c.hash, c.branch, c.pull_request,
c.author, c.gravatar, c.timestamp, c.message, c.created, c.updated
FROM repos r, commits c
WHERE r.user_id = ?
AND r.team_id = 0
AND r.id = c.repo_id
AND c.status IN ('Success', 'Failure')
ORDER BY c.created desc
LIMIT 10
`
// SQL Query to retrieve a list of recent commits by team.
const teamCommitRecentStmt = `
SELECT r.slug, r.host, r.owner, r.name,
c.status, c.started, c.finished, c.duration, c.hash, c.branch, c.pull_request,
c.author, c.gravatar, c.timestamp, c.message, c.created, c.updated
FROM repos r, commits c
WHERE r.team_id = ?
AND r.id = c.repo_id
AND c.status IN ('Success', 'Failure')
ORDER BY c.created desc
LIMIT 10
`
// SQL Queries to delete a Commit.
const commitDeleteStmt = `
DELETE FROM commits WHERE id = ?
`
// SQL Queries to retrieve the latest Commits for each branch.
const commitBranchesStmt = `
SELECT id, repo_id, status, started, finished, duration,
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
FROM commits
WHERE id IN (
SELECT MAX(id)
FROM commits
WHERE repo_id = ?
GROUP BY branch)
ORDER BY branch ASC
`
// SQL Queries to retrieve the latest Commits for each branch.
const commitBranchStmt = `
SELECT id, repo_id, status, started, finished, duration,
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
FROM commits
WHERE id IN (
SELECT MAX(id)
FROM commits
WHERE repo_id = ?
AND branch = ?
GROUP BY branch)
LIMIT 1
`
// Returns the Commit with the given ID.
func GetCommit(id int64) (*Commit, error) {
commit := Commit{}
err := meddler.QueryRow(db, &commit, commitFindStmt, id)
return &commit, err
}
// Returns the Commit with the given hash.
func GetCommitHash(hash string, repo int64) (*Commit, error) {
commit := Commit{}
err := meddler.QueryRow(db, &commit, commitFindHashStmt, hash, repo)
return &commit, err
}
// Returns the most recent Commit for the given branch.
func GetBranch(repo int64, branch string) (*Commit, error) {
commit := Commit{}
err := meddler.QueryRow(db, &commit, commitBranchStmt, repo, branch)
return &commit, err
}
// Creates a new Commit.
func SaveCommit(commit *Commit) error {
if commit.ID == 0 {
commit.Created = time.Now().UTC()
}
commit.Updated = time.Now().UTC()
return meddler.Save(db, commitTable, commit)
}
// Deletes an existing Commit.
func DeleteCommit(id int64) error {
_, err := db.Exec(commitDeleteStmt, id)
return err
}
// Returns a list of all Commits associated
// with the specified Repo ID.
func ListCommits(repo int64, branch string) ([]*Commit, error) {
var commits []*Commit
err := meddler.QueryAll(db, &commits, commitStmt, repo, branch)
return commits, err
}
// Returns a list of recent Commits associated
// with the specified User ID
func ListCommitsUser(user int64) ([]*RepoCommit, error) {
var commits []*RepoCommit
err := meddler.QueryAll(db, &commits, userCommitRecentStmt, user)
return commits, err
}
// Returns a list of recent Commits associated
// with the specified Team ID
func ListCommitsTeam(team int64) ([]*RepoCommit, error) {
var commits []*RepoCommit
err := meddler.QueryAll(db, &commits, teamCommitRecentStmt, team)
return commits, err
}
// Returns a list of the most recent commits for each branch.
func ListBranches(repo int64) ([]*Commit, error) {
var commits []*Commit
err := meddler.QueryAll(db, &commits, commitBranchesStmt, repo)
return commits, err
}

24
pkg/database/database.go Normal file
View File

@@ -0,0 +1,24 @@
package database
import (
"database/sql"
"log"
"github.com/drone/drone/pkg/database/schema"
)
// global instance of our database connection.
var db *sql.DB
// Set sets the default database.
func Set(database *sql.DB) {
// set the global database
db = database
// load the database schema. If this is
// a new database all the tables and
// indexes will be created.
if err := schema.Load(db); err != nil {
log.Fatal(err)
}
}

View File

@@ -0,0 +1,133 @@
package encrypt
import (
"bytes"
"crypto/cipher"
"crypto/rand"
"encoding/gob"
"fmt"
"io"
)
// EncryptedField handles encrypted and decryption of
// values to and from database columns.
type EncryptedField struct {
Cipher cipher.Block
}
// PreRead is called before a Scan operation. It is given a pointer to
// the raw struct field, and returns the value that will be given to
// the database driver.
func (e *EncryptedField) PreRead(fieldAddr interface{}) (scanTarget interface{}, err error) {
// give a pointer to a byte buffer to grab the raw data
return new([]byte), nil
}
// PostRead is called after a Scan operation. It is given the value returned
// by PreRead and a pointer to the raw struct field. It is expected to fill
// in the struct field if the two are different.
func (e *EncryptedField) PostRead(fieldAddr interface{}, scanTarget interface{}) error {
ptr := scanTarget.(*[]byte)
if ptr == nil {
return fmt.Errorf("encrypter.PostRead: nil pointer")
}
raw := *ptr
// ignore fields that aren't set at all
if len(raw) == 0 {
return nil
}
// decrypt value for gob decoding
var err error
raw, err = decrypt(e.Cipher, raw)
if err != nil {
return fmt.Errorf("Gob decryption error: %v", err)
}
// decode gob
gobDecoder := gob.NewDecoder(bytes.NewReader(raw))
if err := gobDecoder.Decode(fieldAddr); err != nil {
return fmt.Errorf("Gob decode error: %v", err)
}
return nil
}
// PreWrite is called before an Insert or Update operation. It is given
// a pointer to the raw struct field, and returns the value that will be
// given to the database driver.
func (e *EncryptedField) PreWrite(field interface{}) (saveValue interface{}, err error) {
buffer := new(bytes.Buffer)
// gob encode
gobEncoder := gob.NewEncoder(buffer)
if err := gobEncoder.Encode(field); err != nil {
return nil, fmt.Errorf("Gob encoding error: %v", err)
}
// and then ecrypt
encrypted, err := encrypt(e.Cipher, buffer.Bytes())
if err != nil {
return nil, fmt.Errorf("Gob decryption error: %v", err)
}
return encrypted, nil
}
// encrypt is a helper function to encrypt a slice
// of bytes using the specified block cipher.
func encrypt(block cipher.Block, v []byte) ([]byte, error) {
// if no block cipher value exists we'll assume
// the database is running in non-ecrypted mode.
if block == nil {
return v, nil
}
value := make([]byte, len(v))
copy(value, v)
// Generate a random initialization vector
iv := generateRandomKey(block.BlockSize())
if len(iv) != block.BlockSize() {
return nil, fmt.Errorf("Could not generate a valid initialization vector for encryption")
}
// Encrypt it.
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(value, value)
// Return iv + ciphertext.
return append(iv, value...), nil
}
// decrypt is a helper function to decrypt a slice
// using the specified block cipher.
func decrypt(block cipher.Block, value []byte) ([]byte, error) {
// if no block cipher value exists we'll assume
// the database is running in non-ecrypted mode.
if block == nil {
return value, nil
}
size := block.BlockSize()
if len(value) > size {
// Extract iv.
iv := value[:size]
// Extract ciphertext.
value = value[size:]
// Decrypt it.
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(value, value)
return value, nil
}
return nil, fmt.Errorf("Could not decrypt the value")
}
// GenerateRandomKey creates a random key of size length bytes
func generateRandomKey(strength int) []byte {
k := make([]byte, strength)
if _, err := io.ReadFull(rand.Reader, k); err != nil {
return nil
}
return k
}

86
pkg/database/members.go Normal file
View File

@@ -0,0 +1,86 @@
package database
import (
. "github.com/drone/drone/pkg/model"
"github.com/russross/meddler"
)
// Name of the Member table in the database
const memberTable = "members"
// SQL Queries to retrieve a list of all members belonging to a team.
const memberStmt = `
SELECT user_id, name, email, gravatar, role
FROM members, users
WHERE users.id = members.user_id
AND team_id = ?
`
// SQL Queries to retrieve a team by id and user.
const memberFindStmt = `
SELECT user_id, name, email, gravatar, role
FROM members, users
WHERE users.id = members.user_id
AND user_id = ?
AND team_id = ?
`
// SQL Queries to retrieve a team by name .
const memberDeleteStmt = `
DELETE FROM members
WHERE user_id = ? AND team_id = ?
`
// SQL Queries to retrieve a member's role by id and user.
const roleFindStmt = `
SELECT role FROM members
WHERE user_id = ? AND team_id = ?
`
// Returns the Member with the given user and team IDs.
func GetMember(user, team int64) (*Member, error) {
member := Member{}
err := meddler.QueryRow(db, &member, memberFindStmt, user, team)
return &member, err
}
// Returns true if the user is a member of the team
func IsMember(user, team int64) (bool, error) {
role := Role{}
err := meddler.QueryRow(db, &role, roleFindStmt, user, team)
return len(role.Role) > 0, err
}
// Returns true is the user is an admin member of the team.
func IsMemberAdmin(user, team int64) (bool, error) {
role := Role{}
err := meddler.QueryRow(db, &role, roleFindStmt, user, team)
return role.Role == RoleAdmin || role.Role == RoleOwner, err
}
// Creates a new Member.
func SaveMember(user, team int64, role string) error {
r := Role{}
if err := meddler.QueryRow(db, &r, roleFindStmt, user, team); err == nil {
r.Role = role
return meddler.Save(db, memberTable, &r)
}
r.UserID = user
r.TeamID = team
r.Role = role
return meddler.Save(db, memberTable, &r)
}
// Deletes an existing Member.
func DeleteMember(user, team int64) error {
_, err := db.Exec(memberDeleteStmt, user, team)
return err
}
// Returns a list of all Team members.
func ListMembers(team int64) ([]*Member, error) {
var members []*Member
err := meddler.QueryAll(db, &members, memberStmt, team)
return members, err
}

92
pkg/database/repos.go Normal file
View File

@@ -0,0 +1,92 @@
package database
import (
"time"
. "github.com/drone/drone/pkg/model"
"github.com/russross/meddler"
)
// Name of the Repos table in the database
const repoTable = "repos"
// SQL Queries to retrieve a list of all repos belonging to a User.
const repoStmt = `
SELECT id, slug, host, owner, name, private, disabled, disabled_pr, scm, url, username, password,
public_key, private_key, params, timeout, priveleged, created, updated, user_id, team_id
FROM repos
WHERE user_id = ? AND team_id = 0
ORDER BY slug ASC
`
// SQL Queries to retrieve a list of all repos belonging to a Team.
const repoTeamStmt = `
SELECT id, slug, host, owner, name, private, disabled, disabled_pr, scm, url, username, password,
public_key, private_key, params, timeout, priveleged, created, updated, user_id, team_id
FROM repos
WHERE team_id = ?
ORDER BY slug ASC
`
// SQL Queries to retrieve a repo by id.
const repoFindStmt = `
SELECT id, slug, host, owner, name, private, disabled, disabled_pr, scm, url, username, password,
public_key, private_key, params, timeout, priveleged, created, updated, user_id, team_id
FROM repos
WHERE id = ?
`
// SQL Queries to retrieve a repo by name.
const repoFindSlugStmt = `
SELECT id, slug, host, owner, name, private, disabled, disabled_pr, scm, url, username, password,
public_key, private_key, params, timeout, priveleged, created, updated, user_id, team_id
FROM repos
WHERE slug = ?
`
// Returns the Repo with the given ID.
func GetRepo(id int64) (*Repo, error) {
repo := Repo{}
err := meddler.QueryRow(db, &repo, repoFindStmt, id)
return &repo, err
}
// Returns the Repo with the given slug.
func GetRepoSlug(slug string) (*Repo, error) {
repo := Repo{}
err := meddler.QueryRow(db, &repo, repoFindSlugStmt, slug)
return &repo, err
}
// Creates a new Repository.
func SaveRepo(repo *Repo) error {
if repo.ID == 0 {
repo.Created = time.Now().UTC()
}
repo.Updated = time.Now().UTC()
return meddler.Save(db, repoTable, repo)
}
// Deletes an existing Repository.
// TODO need to delete builds too.
func DeleteRepo(id int64) error {
_, err := db.Exec("DELETE FROM repos WHERE id = ?", id)
db.Exec("DELETE FROM commits WHERE repo_id = ?", id)
return err
}
// Returns a list of all Repos associated
// with the specified User ID.
func ListRepos(id int64) ([]*Repo, error) {
var repos []*Repo
err := meddler.QueryAll(db, &repos, repoStmt, id)
return repos, err
}
// Returns a list of all Repos associated
// with the specified Team ID.
func ListReposTeam(id int64) ([]*Repo, error) {
var repos []*Repo
err := meddler.QueryAll(db, &repos, repoTeamStmt, id)
return repos, err
}

View File

@@ -0,0 +1,126 @@
DELETE FROM builds;
DELETE FROM commits;
DELETE FROM repos;
DELETE FROM members;
DELETE FROM teams;
DELETE FROM users;
DELETE FROM settings;
-- insert users (default password is "password")
INSERT INTO users values (1, 'brad.rydzewski@gmail.com' , '$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS', 'nPmsbl6YNLUIUo0I7gkMcQ' ,'Brad Rydzewski', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, '', '', '', '', '');
INSERT INTO users values (2, 'thomas.d.burke@gmail.com' , '$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS', 'sal5Tzy6S10yZCaE0jl6QA', 'Thomas Burke', 'c62f7126273f7fa786274274a5dec8ce', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, '', '', '', '', '');
INSERT INTO users values (3, 'carlos.morales.duran@gmail.com', '$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS', 'bq87o8AmDUOahKApEy2tVQ', 'Carlos Morales', 'c2180a539620d90d68eaeb848364f1c2', '2013-09-16 00:00:00', '2013-09-17 00:00:00', 1, '', '', '', '', '');
-- insert teams
insert into teams values (1, 'drone', 'Drone' , 'brad@drone.io' , '0057e90a8036c29b1ddb22d0fd08b72c', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
insert into teams values (2, 'google', 'Google', 'dev@google.com' , '24ba30616d2a20673f54c2aee36d159e', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
insert into teams values (3, 'gradle', 'Gradle', 'dev@gradle.com' , '5cc3b557e3a3978d52036da9a5be2a08', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
insert into teams values (4, 'dart', 'Dart' , 'dev@dartlang.org', 'f41fe13f979f2f93cc8b971e1875bdf8', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
-- insert team members
insert into members values (1, 1, 1, 'Owner');
insert into members values (2, 1, 2, 'Admin');
insert into members values (3, 1, 3, 'Write');
-- insert repository
insert into repos values (1, 'github.com/drone/jkl', 'github.com', 'drone', 'jkl', 0, 0, 0, 0, 900, 'git', 'git://github.com/drone/jkl.git', '', '', '', '', '', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, 1);
insert into repos values (2, 'github.com/drone/drone', 'github.com', 'drone', 'drone', 1, 0, 0, 0, 900, 'git', 'git@github.com:drone/drone.git', '', '', '', '', '', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, 1);
insert into repos values (3, 'github.com/bradrydzewski/drone', 'github.com', 'bradrydzewski', 'drone', 1, 0, 0, 0, 900, 'git', 'git@github.com:bradrydzewski/drone.git', '', '', '', '', '', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, 1);
insert into repos values (4, 'github.com/bradrydzewski/blog', 'github.com', 'bradrydzewski', 'blog', 0, 0, 0, 0, 900, 'git', 'git://github.com/bradrydzewski/blog.git', '', '', '', '', '', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, 0);
-- insert commits
insert into commits values (1, 1, 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, 'ef2221722e6f07a6eaf8af8907b45324428a891d', 'master', '','brad.rydzewski@gmail.com', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', 'Fixed mock db class for entity', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
insert into commits values (2, 1, 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '867477aa487d01df28522cee84cd06f5aa154e53', 'master', '','brad.rydzewski@gmail.com', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', 'Fixed mock db class for entity', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
insert into commits values (3, 1, 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, 'e43427ab462417cb3d53b8702c298c1675deb926', 'master', '','brad.rydzewski@gmail.com', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', 'Save deleted entity data to database', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
insert into commits values (4, 1, 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, 'a43427ab462417cb3d53b8702c298c1675deb926', 'dev', '','brad.rydzewski@gmail.com', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', 'Save deleted entity data to database', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
-- insert builds
insert into builds values (1, 1, 'node_0.10', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
insert into builds values (2, 1, 'node_0.90', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
insert into builds values (3, 1, 'node_0.80', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
insert into builds values (4, 2, 'node_0.10', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
insert into builds values (5, 2, 'node_0.90', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
insert into builds values (6, 2, 'node_0.80', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
insert into builds values (7, 3, 'node_0.10', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
insert into builds values (8, 3, 'node_0.90', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
insert into builds values (9, 3, 'node_0.80', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
-- insert default, dummy settings
insert into settings values (1,'','','','','','','','','','localhost:8080','http');
-- add public & private keys to all repositories
update repos set public_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCybgl9+Y0VY0mKng3AB3CwCMAOVvg+Xh4X/4lP7SR815GaeEJQusaA0p33HkZfS/2XREWYMtiopHP0bZuBIht76JdhrJlHh1AcLoPQvWJROFvRGol6igVEVZzs9sUdZaPrexFz1CS/j6BJFzPsHnL4gXT3s4PYYST9++pThI90Aw==';
update repos set private_key = '-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCybgl9+Y0VY0mKng3AB3CwCMAOVvg+Xh4X/4lP7SR815GaeEJQ
usaA0p33HkZfS/2XREWYMtiopHP0bZuBIht76JdhrJlHh1AcLoPQvWJROFvRGol6
igVEVZzs9sUdZaPrexFz1CS/j6BJFzPsHnL4gXT3s4PYYST9++pThI90AwIDAQAB
AoGAaxvs7MdaLsWcRu7cGDMfLT0DdVg1ytKaxBMsrWMQrTSGfjDEtkt4j6pfExIE
cn5ea2ibUmLrdkjKJqeJWrpLvlOZGhahBcL/SueFOfr6Lm+m8LvlTrX6JhyLXpx5
NbeEFr0mN16PC6JqkN0xRCN9BfV9m6gnpuP/ojD3RKYMZtkCQQDFbSX/ddEfp9ME
vRNAYif+bFxI6PEgMmwrCIjJGHOsq7zba3Z7KWjW034x2rJ3Cbhs8xtyTcA5qy9F
OzL3pFs3AkEA514SUXowIiqjh6ypnSvUBaQZsWjexDxTXN09DTYPt+Ck1qdzTHWP
9nerg2G3B6bTOWZBftHMaZ/plZ/eyV0LlQJACU1rTO4wPF2cA80k6xO07rgMYSMY
uXumvSBZ0Z/lU22EKJKXspXw6q5sc8zqO9GpbvjFgk1HkXAPeiOf8ys7YQJAD1CI
wd/mo7xSyr5BE+g8xorQMJASfsbHddQnIGK9s5wpDRRUa3E0sEnHjpC/PsBqJth/
6VcVwsAVBBRq+MUx6QJAS9KKxKcMf8JpnDheV7jh+WJKckabA1L2bq8sN6kXfPn0
o7deiE1FKJizXKJ6gd6anfuG3m7VAs7wJhzc685yMg==
-----END RSA PRIVATE KEY-----';
-- add standard output to all builds
update builds set stdout = '$ mvn test
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running brooklyn.qa.longevity.MonitorUtilsTest
Configuring TestNG with: TestNG652Configurator
[GC 69952K->6701K(253440K), 0.0505760 secs]
2013-08-21 21:12:58,327 INFO TESTNG RUNNING: Suite: "Command line test" containing "7" Tests (config: null)
2013-08-21 21:12:58,342 INFO BrooklynLeakListener.onStart attempting to terminate all extant ManagementContexts: name=Command line test; includedGroups=[]; excludedGroups=[Integration, Acceptance, Live, WIP]; suiteName=brooklyn.qa.longevity.MonitorUtilsTest; outDir=/scratch/jenkins/workspace/brooklyncentral/brooklyn/usage/qa/target/surefire-reports/brooklyn.qa.longevity.MonitorUtilsTest
2013-08-21 21:12:58,473 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testFindOwnPid()
2013-08-21 21:12:58,939 INFO executing cmd: ps -p 7484
2013-08-21 21:12:59,030 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testFindOwnPid() finished in 595 ms
2013-08-21 21:12:59,033 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testGetRunningPids()
2013-08-21 21:12:59,035 INFO executing cmd: ps ax
2013-08-21 21:12:59,137 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testGetRunningPids() finished in 104 ms
2013-08-21 21:12:59,139 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testGroovyExecuteAndWaitForConsumingOutputStream()
2013-08-21 21:12:59,295 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testGroovyExecuteAndWaitForConsumingOutputStream() finished in 155 ms
2013-08-21 21:12:59,298 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testIsPidRunning()
2013-08-21 21:12:59,300 INFO executing cmd: ps ax
2013-08-21 21:12:59,384 INFO executing cmd: ps -p 7484
2013-08-21 21:12:59,391 INFO executing cmd: ps -p 10000
2013-08-21 21:12:59,443 INFO pid 10000 not running:
2013-08-21 21:12:59,446 INFO executing cmd: ps -p 1234567
2013-08-21 21:12:59,455 INFO pid 1234567 not running:
2013-08-21 21:12:59,456 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testIsPidRunning() finished in 158 ms
2013-08-21 21:12:59,481 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testIsUrlUp()
[GC 76653K->7013K(253440K), 0.0729880 secs]
2013-08-21 21:13:00,726 INFO Error reading URL http://localhost/thispathdoesnotexist: org.apache.http.conn.HttpHostConnectException: Connection to http://localhost refused
2013-08-21 21:13:00,727 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testIsUrlUp() finished in 1246 ms
2013-08-21 21:13:00,760 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testMemoryUsage()
2013-08-21 21:13:00,762 INFO executing cmd: jmap -histo 7484
2013-08-21 21:13:02,275 INFO executing cmd: jmap -histo 7484
2013-08-21 21:13:03,690 INFO executing cmd: jmap -histo 7484
2013-08-21 21:13:04,725 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testMemoryUsage() finished in 3965 ms
2013-08-21 21:13:04,752 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testSearchLog()
2013-08-21 21:13:04,816 INFO executing cmd: grep -E line1 /tmp/monitorUtilsTest.testSearchLog2369184699231420767.txt
2013-08-21 21:13:04,848 INFO executing cmd: grep -E line1|line2 /tmp/monitorUtilsTest.testSearchLog2369184699231420767.txt
2013-08-21 21:13:04,854 INFO executing cmd: grep -E textnotthere /tmp/monitorUtilsTest.testSearchLog2369184699231420767.txt
2013-08-21 21:13:04,858 INFO executing cmd: grep -E line /tmp/monitorUtilsTest.testSearchLog2369184699231420767.txt
2013-08-21 21:13:04,897 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testSearchLog() finished in 145 ms
2013-08-21 21:13:04,917 INFO TESTNG
===============================================
Command line test
Tests run: 7, Failures: 0, Skips: 0
===============================================
2013-08-21 21:13:04,944 INFO BrooklynLeakListener.onFinish attempting to terminate all extant ManagementContexts: name=Command line test; includedGroups=[]; excludedGroups=[Integration, Acceptance, Live, WIP]; suiteName=brooklyn.qa.longevity.MonitorUtilsTest; outDir=/scratch/jenkins/workspace/brooklyncentral/brooklyn/usage/qa/target/surefire-reports/brooklyn.qa.longevity.MonitorUtilsTest
Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 10.849 sec
Results :
Tests run: 7, Failures: 0, Errors: 0, Skipped: 0';

View File

@@ -0,0 +1,198 @@
package schema
import (
"database/sql"
)
// SQL statement to create the User Table.
var userTableStmt = `
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT
,email VARCHAR(255) UNIQUE
,password VARCHAR(255)
,token VARCHAR(255) UNIQUE
,name VARCHAR(255)
,gravatar VARCHAR(255)
,created TIMESTAMP
,updated TIMESTAMP
,admin BOOLEAN
,github_login VARCHAR(255)
,github_token VARCHAR(255)
,bitbucket_login VARCHAR(255)
,bitbucket_token VARCHAR(255)
,bitbucket_secret VARCHAR(255)
);
`
// SQL statement to create the Team Table.
var teamTableStmt = `
CREATE TABLE teams (
id INTEGER PRIMARY KEY AUTOINCREMENT
,slug VARCHAR(255) UNIQUE
,name VARCHAR(255)
,email VARCHAR(255)
,gravatar VARCHAR(255)
,created TIMESTAMP
,updated TIMESTAMP
);
`
// SQL statement to create the Member Table.
var memberTableStmt = `
CREATE TABLE members (
id INTEGER PRIMARY KEY AUTOINCREMENT
,team_id INTEGER
,user_id INTEGER
,role INTEGER
);
`
// SQL statement to create the Repo Table.
var repoTableStmt = `
CREATE TABLE repos (
id INTEGER PRIMARY KEY AUTOINCREMENT
,slug VARCHAR(1024) UNIQUE
,host VARCHAR(255)
,owner VARCHAR(255)
,name VARCHAR(255)
,private BOOLEAN
,disabled BOOLEAN
,disabled_pr BOOLEAN
,priveleged BOOLEAN
,timeout INTEGER
,scm VARCHAR(25)
,url VARCHAR(1024)
,username VARCHAR(255)
,password VARCHAR(255)
,public_key VARCHAR(1024)
,private_key VARCHAR(1024)
,params VARCHAR(2000)
,created TIMESTAMP
,updated TIMESTAMP
,user_id INTEGER
,team_id INTEGER
);
`
// SQL statement to create the Commit Table.
var commitTableStmt = `
CREATE TABLE commits (
id INTEGER PRIMARY KEY AUTOINCREMENT
,repo_id INTEGER
,status VARCHAR(255)
,started TIMESTAMP
,finished TIMESTAMP
,duration INTEGER
,attempts INTEGER
,hash VARCHAR(255)
,branch VARCHAR(255)
,pull_request VARCHAR(255)
,author VARCHAR(255)
,gravatar VARCHAR(255)
,timestamp VARCHAR(255)
,message VARCHAR(255)
,created TIMESTAMP
,updated TIMESTAMP
);
`
// SQL statement to create the Build Table.
var buildTableStmt = `
CREATE TABLE builds (
id INTEGER PRIMARY KEY AUTOINCREMENT
,commit_id INTEGER
,slug VARCHAR(255)
,status VARCHAR(255)
,started TIMESTAMP
,finished TIMESTAMP
,duration INTEGER
,created TIMESTAMP
,updated TIMESTAMP
,stdout BLOB
);
`
// SQL statement to create the Settings
var settingsTableStmt = `
CREATE TABLE settings (
id INTEGER PRIMARY KEY
,github_key VARCHAR(255)
,github_secret VARCHAR(255)
,bitbucket_key VARCHAR(255)
,bitbucket_secret VARCHAR(255)
,smtp_server VARCHAR(1024)
,smtp_port VARCHAR(5)
,smtp_address VARCHAR(1024)
,smtp_username VARCHAR(1024)
,smtp_password VARCHAR(1024)
,hostname VARCHAR(1024)
,scheme VARCHAR(5)
);
`
var memberUniqueIndex = `
CREATE UNIQUE INDEX member_uix ON members (team_id, user_id);
`
var memberTeamIndex = `
CREATE INDEX member_team_ix ON members (team_id);
`
var memberUserIndex = `
CREATE INDEX member_user_ix ON members (user_id);
`
var commitUniqueIndex = `
CREATE UNIQUE INDEX commits_uix ON commits (repo_id, hash, branch);
`
var commitRepoIndex = `
CREATE INDEX commits_repo_ix ON commits (repo_id);
`
var commitBranchIndex = `
CREATE INDEX commits_repo_ix ON commits (repo_id, branch);
`
var repoTeamIndex = `
CREATE INDEX repo_team_ix ON repos (team_id);
`
var repoUserIndex = `
CREATE INDEX repo_user_ix ON repos (user_id);
`
var buildCommitIndex = `
CREATE INDEX builds_commit_ix ON builds (commit_id);
`
var buildSlugIndex = `
CREATE INDEX builds_commit_slug_ix ON builds (commit_id, slug);
`
// Load will apply the DDL commands to
// the provided database.
func Load(db *sql.DB) error {
// created tables
db.Exec(userTableStmt)
db.Exec(teamTableStmt)
db.Exec(memberTableStmt)
db.Exec(repoTableStmt)
db.Exec(commitTableStmt)
db.Exec(buildTableStmt)
db.Exec(settingsTableStmt)
db.Exec(memberUniqueIndex)
db.Exec(memberTeamIndex)
db.Exec(memberUserIndex)
db.Exec(commitUniqueIndex)
db.Exec(commitRepoIndex)
db.Exec(commitBranchIndex)
db.Exec(repoTeamIndex)
db.Exec(repoUserIndex)
db.Exec(buildCommitIndex)
db.Exec(buildSlugIndex)
return nil
}

View File

@@ -0,0 +1,127 @@
DROP TABLE IF EXISTS builds;
DROP TABLE IF EXISTS commits;
DROP TABLE IF EXISTS repos;
DROP TABLE IF EXISTS members;
DROP TABLE IF EXISTS teams;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS settings;
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT
,email VARCHAR(255) UNIQUE
,password VARCHAR(255)
,token VARCHAR(255) UNIQUE
,name VARCHAR(255)
,gravatar VARCHAR(255)
,created TIMESTAMP
,updated TIMESTAMP
,admin BOOLEAN
,github_login VARCHAR(255)
,github_token VARCHAR(255)
,bitbucket_login VARCHAR(255)
,bitbucket_token VARCHAR(255)
,bitbucket_secret VARCHAR(255)
);
CREATE TABLE teams (
id INTEGER PRIMARY KEY AUTOINCREMENT
,slug VARCHAR(255) UNIQUE
,name VARCHAR(255) UNIQUE
,email VARCHAR(255)
,gravatar VARCHAR(255)
,created TIMESTAMP
,updated TIMESTAMP
);
CREATE TABLE members (
id INTEGER PRIMARY KEY AUTOINCREMENT
,team_id INTEGER
,user_id INTEGER
,role INTEGER
);
CREATE TABLE repos (
id INTEGER PRIMARY KEY AUTOINCREMENT
,slug VARCHAR(1024) UNIQUE
,host VARCHAR(255)
,owner VARCHAR(255)
,name VARCHAR(255)
,private BOOLEAN
,disabled BOOLEAN
,disabled_pr BOOLEAN
,priveleged BOOLEAN
,timeout INTEGER
,scm VARCHAR(25)
,url VARCHAR(1024)
,username VARCHAR(255)
,password VARCHAR(255)
,public_key VARCHAR(1024)
,private_key VARCHAR(1024)
,params VARCHAR(2000)
,created TIMESTAMP
,updated TIMESTAMP
,user_id INTEGER
,team_id INTEGER
);
CREATE TABLE commits (
id INTEGER PRIMARY KEY AUTOINCREMENT
,repo_id INTEGER
,status VARCHAR(255)
,started TIMESTAMP
,finished TIMESTAMP
,duration INTEGER
,hash VARCHAR(255)
,branch VARCHAR(255)
,pull_request VARCHAR(255)
,author VARCHAR(255)
,gravatar VARCHAR(255)
,timestamp VARCHAR(255)
,message VARCHAR(255)
,created TIMESTAMP
,updated TIMESTAMP
);
CREATE TABLE builds (
id INTEGER PRIMARY KEY AUTOINCREMENT
,commit_id INTEGER
,slug VARCHAR(255)
,status VARCHAR(255)
,started TIMESTAMP
,finished TIMESTAMP
,duration INTEGER
,created TIMESTAMP
,updated TIMESTAMP
,stdout BLOB
);
CREATE TABLE settings (
id INTEGER PRIMARY KEY
,github_key VARCHAR(255)
,github_secret VARCHAR(255)
,bitbucket_key VARCHAR(255)
,bitbucket_secret VARCHAR(255)
,smtp_server VARCHAR(1024)
,smtp_port VARCHAR(5)
,smtp_address VARCHAR(1024)
,smtp_username VARCHAR(1024)
,smtp_password VARCHAR(1024)
,hostname VARCHAR(1024)
,scheme VARCHAR(5)
);
CREATE UNIQUE INDEX member_uix ON members (team_id, user_id);
CREATE UNIQUE INDEX commits_uix ON commits (repo_id, hash, branch);
CREATE INDEX member_team_ix ON members (team_id);
CREATE INDEX member_user_ix ON members (user_id);
CREATE INDEX repo_team_ix ON repos (team_id);
CREATE INDEX repo_user_ix ON repos (user_id);
CREATE INDEX commits_repo_ix ON commits (repo_id);
CREATE INDEX commits_repo_branch_ix ON commits (repo_id, branch);
CREATE INDEX builds_commit_ix ON builds (commit_id);
CREATE INDEX builds_commit_slug_ix ON builds (commit_id, slug);

72
pkg/database/settings.go Normal file
View File

@@ -0,0 +1,72 @@
package database
import (
. "github.com/drone/drone/pkg/model"
"github.com/russross/meddler"
)
// Name of the Settings table in the database
const settingsTable = "settings"
// SQL Queries to retrieve the system settings
const settingsStmt = `
SELECT id, github_key, github_secret, bitbucket_key, bitbucket_secret,
smtp_server, smtp_port, smtp_address, smtp_username, smtp_password, hostname, scheme
FROM settings WHERE id = 1
`
//var (
// // mutex for locking the local settings cache
// settingsLock sync.Mutex
//
// // cached settings
// settingsCache = &Settings{}
//)
// Returns the system Settings.
func GetSettings() (*Settings, error) {
//settingsLock.Lock()
//defer settingsLock.Unlock()
// return a copy of the settings
//if settingsCache.ID == 0 {
/// settingsCopy := &Settings{}
// *settingsCopy = *settingsCache
// return settingsCopy, nil
//}
settings := Settings{}
err := meddler.QueryRow(db, &settings, settingsStmt)
//if err == sql.ErrNoRows {
// // we ignore the NoRows error in case this
// // is the first time the system is being used
// err = nil
//}
return &settings, err
}
// Returns the system Settings. This is expected
// always pass, and will panic on failure.
func SettingsMust() *Settings {
settings, err := GetSettings()
if err != nil {
panic(err)
}
return settings
}
// Saves the system Settings.
func SaveSettings(settings *Settings) error {
//settingsLock.Lock()
//defer settingsLock.Unlock()
// persist changes to settings
err := meddler.Save(db, settingsTable, settings)
if err != nil {
return err
}
// store updated settings in cache
//*settingsCache = *settings
return nil
}

73
pkg/database/teams.go Normal file
View File

@@ -0,0 +1,73 @@
package database
import (
"time"
. "github.com/drone/drone/pkg/model"
"github.com/russross/meddler"
)
// Name of the Team table in the database
const teamTable = "teams"
// SQL Queries to retrieve a list of all teams belonging to a user.
const teamStmt = `
SELECT id, slug, name, email, gravatar, created, updated
FROM teams
WHERE id IN (select team_id from members where user_id = ?)
`
// SQL Queries to retrieve a team by id and user.
const teamFindStmt = `
SELECT id, slug, name, email, gravatar, created, updated
FROM teams
WHERE id = ?
`
// SQL Queries to retrieve a team by slug.
const teamFindSlugStmt = `
SELECT id, slug, name, email, gravatar, created, updated
FROM teams
WHERE slug = ?
`
// Returns the Team with the given ID.
func GetTeam(id int64) (*Team, error) {
team := Team{}
err := meddler.QueryRow(db, &team, teamFindStmt, id)
return &team, err
}
// Returns the Team with the given slug.
func GetTeamSlug(slug string) (*Team, error) {
team := Team{}
err := meddler.QueryRow(db, &team, teamFindSlugStmt, slug)
return &team, err
}
// Saves a Team.
func SaveTeam(team *Team) error {
if team.ID == 0 {
team.Created = time.Now().UTC()
}
team.Updated = time.Now().UTC()
return meddler.Save(db, teamTable, team)
}
// Deletes an existing Team account.
func DeleteTeam(id int64) error {
// disassociate all repos with this team
db.Exec("UPDATE repos SET team_id = 0 WHERE team_id = ?", id)
// delete the team memberships and the team itself
db.Exec("DELETE FROM members WHERE team_id = ?", id)
db.Exec("DELETE FROM teams WHERE id = ?", id)
return nil
}
// Returns a list of all Teams associated
// with the specified User ID.
func ListTeams(id int64) ([]*Team, error) {
var teams []*Team
err := meddler.QueryAll(db, &teams, teamStmt, id)
return teams, err
}

View File

@@ -0,0 +1,136 @@
package database
import (
"testing"
"github.com/drone/drone/pkg/database"
)
func TestGetBuild(t *testing.T) {
Setup()
defer Teardown()
build, err := database.GetBuild(1)
if err != nil {
t.Error(err)
}
if build.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, build.ID)
}
if build.Slug != "node_0.10" {
t.Errorf("Exepected Slug %s, got %s", "node_0.10", build.Slug)
}
if build.Status != "Success" {
t.Errorf("Exepected Status %s, got %s", "Success", build.Status)
}
}
func TestGetBuildSlug(t *testing.T) {
Setup()
defer Teardown()
build, err := database.GetBuildSlug("node_0.10", 1)
if err != nil {
t.Error(err)
}
if build.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, build.ID)
}
if build.Slug != "node_0.10" {
t.Errorf("Exepected Slug %s, got %s", "node_0.10", build.Slug)
}
if build.Status != "Success" {
t.Errorf("Exepected Status %s, got %s", "Success", build.Status)
}
}
func TestSaveBbuild(t *testing.T) {
Setup()
defer Teardown()
// get the build we plan to update
build, err := database.GetBuild(1)
if err != nil {
t.Error(err)
}
// update fields
build.Status = "Failing"
// update the database
if err := database.SaveBuild(build); err != nil {
t.Error(err)
}
// get the updated build
updatedBuild, err := database.GetBuild(1)
if err != nil {
t.Error(err)
}
if build.ID != updatedBuild.ID {
t.Errorf("Exepected ID %d, got %d", updatedBuild.ID, build.ID)
}
if build.Slug != updatedBuild.Slug {
t.Errorf("Exepected Slug %s, got %s", updatedBuild.Slug, build.Slug)
}
if build.Status != updatedBuild.Status {
t.Errorf("Exepected Status %s, got %s", updatedBuild.Status, build.Status)
}
}
func TestDeleteBuild(t *testing.T) {
Setup()
defer Teardown()
if err := database.DeleteBuild(1); err != nil {
t.Error(err)
}
// try to get the deleted row
_, err := database.GetBuild(1)
if err == nil {
t.Fail()
}
}
func TestListBuilds(t *testing.T) {
Setup()
defer Teardown()
// builds for commit_id = 1
builds, err := database.ListBuilds(1)
if err != nil {
t.Error(err)
}
// verify user count
if len(builds) != 2 {
t.Errorf("Exepected %d builds in database, got %d", 2, len(builds))
return
}
// get the first user in the list and verify
// fields are being populated correctly
build := builds[1]
if build.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, build.ID)
}
if build.Slug != "node_0.10" {
t.Errorf("Exepected Slug %s, got %s", "node_0.10", build.Slug)
}
if build.Status != "Success" {
t.Errorf("Exepected Status %s, got %s", "Success", build.Status)
}
}

View File

@@ -0,0 +1,164 @@
package database
import (
"testing"
"github.com/drone/drone/pkg/database"
)
func TestGetCommit(t *testing.T) {
Setup()
defer Teardown()
commit, err := database.GetCommit(1)
if err != nil {
t.Error(err)
}
if commit.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, commit.ID)
}
if commit.Status != "Success" {
t.Errorf("Exepected Status %s, got %s", "Success", commit.Status)
}
if commit.Hash != "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608" {
t.Errorf("Exepected Hash %s, got %s", "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608", commit.Hash)
}
if commit.Branch != "master" {
t.Errorf("Exepected Branch %s, got %s", "master", commit.Branch)
}
if commit.Author != "brad.rydzewski@gmail.com" {
t.Errorf("Exepected Author %s, got %s", "master", commit.Author)
}
if commit.Message != "commit message" {
t.Errorf("Exepected Message %s, got %s", "master", commit.Message)
}
if commit.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", commit.Gravatar)
}
}
func TestGetCommitHash(t *testing.T) {
Setup()
defer Teardown()
commit, err := database.GetCommitHash("4f4c4594be6d6ddbc1c0dd521334f7ecba92b608", 1)
if err != nil {
t.Error(err)
}
if commit.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, commit.ID)
}
if commit.Hash != "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608" {
t.Errorf("Exepected Hash %s, got %s", "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608", commit.Hash)
}
if commit.Status != "Success" {
t.Errorf("Exepected Status %s, got %s", "Success", commit.Status)
}
}
func TestSaveCommit(t *testing.T) {
Setup()
defer Teardown()
// get the commit we plan to update
commit, err := database.GetCommit(1)
if err != nil {
t.Error(err)
}
// update fields
commit.Status = "Failing"
// update the database
if err := database.SaveCommit(commit); err != nil {
t.Error(err)
}
// get the updated commit
updatedCommit, err := database.GetCommit(1)
if err != nil {
t.Error(err)
}
if commit.Hash != updatedCommit.Hash {
t.Errorf("Exepected Hash %s, got %s", updatedCommit.Hash, commit.Hash)
}
if commit.Status != "Failing" {
t.Errorf("Exepected Status %s, got %s", updatedCommit.Status, commit.Status)
}
}
func TestDeleteCommit(t *testing.T) {
Setup()
defer Teardown()
if err := database.DeleteCommit(1); err != nil {
t.Error(err)
}
// try to get the deleted row
_, err := database.GetCommit(1)
if err == nil {
t.Fail()
}
}
func TestListCommits(t *testing.T) {
Setup()
defer Teardown()
// commits for repo_id = 1
commits, err := database.ListCommits(1, "master")
if err != nil {
t.Error(err)
}
// verify commit count
if len(commits) != 2 {
t.Errorf("Exepected %d commits in database, got %d", 2, len(commits))
return
}
// get the first user in the list and verify
// fields are being populated correctly
commit := commits[1] // TODO something strange is happening with ordering here
if commit.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, commit.ID)
}
if commit.Status != "Success" {
t.Errorf("Exepected Status %s, got %s", "Success", commit.Status)
}
if commit.Hash != "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608" {
t.Errorf("Exepected Hash %s, got %s", "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608", commit.Hash)
}
if commit.Branch != "master" {
t.Errorf("Exepected Branch %s, got %s", "master", commit.Branch)
}
if commit.Author != "brad.rydzewski@gmail.com" {
t.Errorf("Exepected Author %s, got %s", "master", commit.Author)
}
if commit.Message != "commit message" {
t.Errorf("Exepected Message %s, got %s", "master", commit.Message)
}
if commit.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", commit.Gravatar)
}
}

View File

@@ -0,0 +1,140 @@
package database
import (
"testing"
"github.com/drone/drone/pkg/database"
"github.com/drone/drone/pkg/model"
)
// TODO unit test to verify unique constraint on Team.Name
// TestGetMember tests the ability to retrieve a Team
// Member from the database by Unique ID.
func TestGetMember(t *testing.T) {
Setup()
defer Teardown()
// get member by user_id and team_id
member, err := database.GetMember(1, 1)
if err != nil {
t.Error(err)
}
if member.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, member.ID)
}
if member.Name != "Brad Rydzewski" {
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", member.Name)
}
if member.Email != "brad.rydzewski@gmail.com" {
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", member.Email)
}
if member.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", member.Gravatar)
}
if member.Role != model.RoleOwner {
t.Errorf("Exepected Role %s, got %s", model.RoleOwner, member.Role)
}
}
func TestIsMember(t *testing.T) {
Setup()
defer Teardown()
ok, err := database.IsMember(1, 1)
if err != nil {
t.Error(err)
}
if !ok {
t.Errorf("Expected IsMember to return true, returned false")
}
}
func TestIsMemberAdmin(t *testing.T) {
Setup()
defer Teardown()
// expecting user is Owner
if ok, err := database.IsMemberAdmin(1, 1); err != nil {
t.Error(err)
} else if !ok {
t.Errorf("Expected IsMemberAdmin to return true, returned false")
}
// expecting user is Admin
if ok, err := database.IsMemberAdmin(2, 1); err != nil {
t.Error(err)
} else if !ok {
t.Errorf("Expected IsMemberAdmin to return true, returned false")
}
// expecting user is NOT Admin (Write role)
if ok, err := database.IsMemberAdmin(3, 1); err != nil {
t.Error(err)
} else if ok {
t.Errorf("Expected IsMemberAdmin to return false, returned true")
}
}
func TestDeleteMember(t *testing.T) {
Setup()
defer Teardown()
// delete member by user_id and team_id
if err := database.DeleteMember(1, 1); err != nil {
t.Error(err)
}
// get member by user_id and team_id
if _, err := database.GetMember(1, 1); err == nil {
t.Error(err)
}
}
func TestListMembers(t *testing.T) {
Setup()
defer Teardown()
// list members by team_id
members, err := database.ListMembers(1)
if err != nil {
t.Error(err)
}
// verify team count
if len(members) != 3 {
t.Errorf("Exepected %d Team Members in database, got %d", 3, len(members))
return
}
// get the first member in the list and verify
// fields are being populated correctly
member := members[0]
if member.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, member.ID)
}
if member.Name != "Brad Rydzewski" {
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", member.Name)
}
if member.Email != "brad.rydzewski@gmail.com" {
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", member.Email)
}
if member.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", member.Gravatar)
}
if member.Role != model.RoleOwner {
t.Errorf("Exepected Role %s, got %s", model.RoleOwner, member.Role)
}
}

View File

@@ -0,0 +1,403 @@
package database
import (
"testing"
"github.com/drone/drone/pkg/database"
)
// TODO unit test to verify unique constraint on Member.UserID and Member.TeamID
// TestGetRepo tests the ability to retrieve a Repo
// from the database by Unique ID.
func TestGetRepo(t *testing.T) {
Setup()
defer Teardown()
repo, err := database.GetRepo(1)
if err != nil {
t.Error(err)
}
if repo.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.ID)
}
if repo.Slug != "github.com/drone/drone" {
t.Errorf("Exepected Slug %s, got %s", "github.com/drone/drone", repo.Slug)
}
if repo.Host != "github.com" {
t.Errorf("Exepected Host %s, got %s", "github.com", repo.Host)
}
if repo.Owner != "drone" {
t.Errorf("Exepected Owner %s, got %s", "drone", repo.Owner)
}
if repo.Name != "drone" {
t.Errorf("Exepected Name %s, got %s", "drone", repo.Name)
}
if repo.Private != true {
t.Errorf("Exepected Private %v, got %v", true, repo.Private)
}
if repo.Disabled != false {
t.Errorf("Exepected Private %v, got %v", false, repo.Disabled)
}
if repo.SCM != "git" {
t.Errorf("Exepected Type %s, got %s", "git", repo.SCM)
}
if repo.URL != "git@github.com:drone/drone.git" {
t.Errorf("Exepected URL %s, got %s", "git@github.com:drone/drone.git", repo.URL)
}
if repo.Username != "no username" {
t.Errorf("Exepected Username %s, got %s", "no username", repo.Username)
}
if repo.Password != "no password" {
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
}
if repo.PublicKey != "public key" {
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
}
if repo.PrivateKey != "private key" {
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
}
if repo.UserID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.UserID)
}
if repo.TeamID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.TeamID)
}
}
// TestGetRepoSlug tests the ability to retrieve a Repo
// from the database by it's Canonical Name.
func TestGetRepoSlug(t *testing.T) {
Setup()
defer Teardown()
repo, err := database.GetRepoSlug("github.com/drone/drone")
if err != nil {
t.Error(err)
}
if repo.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.ID)
}
if repo.Slug != "github.com/drone/drone" {
t.Errorf("Exepected Slug %s, got %s", "github.com/drone/drone", repo.Slug)
}
if repo.Host != "github.com" {
t.Errorf("Exepected Host %s, got %s", "github.com", repo.Host)
}
if repo.Owner != "drone" {
t.Errorf("Exepected Owner %s, got %s", "drone", repo.Owner)
}
if repo.Name != "drone" {
t.Errorf("Exepected Name %s, got %s", "drone", repo.Name)
}
if repo.Private != true {
t.Errorf("Exepected Private %v, got %v", true, repo.Private)
}
if repo.Disabled != false {
t.Errorf("Exepected Private %v, got %v", false, repo.Disabled)
}
if repo.SCM != "git" {
t.Errorf("Exepected Type %s, got %s", "git", repo.SCM)
}
if repo.URL != "git@github.com:drone/drone.git" {
t.Errorf("Exepected URL %s, got %s", "git@github.com:drone/drone.git", repo.URL)
}
if repo.Username != "no username" {
t.Errorf("Exepected Username %s, got %s", "no username", repo.Username)
}
if repo.Password != "no password" {
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
}
if repo.PublicKey != "public key" {
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
}
if repo.PrivateKey != "private key" {
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
}
if repo.UserID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.UserID)
}
if repo.TeamID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.TeamID)
}
}
func TestSaveRepo(t *testing.T) {
Setup()
defer Teardown()
// get the repo we plan to update
repo, err := database.GetRepo(1)
if err != nil {
t.Error(err)
}
// update fields
repo.Slug = "bitbucket.org/drone/drone"
repo.Host = "bitbucket.org"
repo.Private = false
repo.Disabled = true
repo.SCM = "hg"
repo.URL = "https://bitbucket.org/drone/drone"
repo.Username = "brad"
repo.Password = "password"
repo.TeamID = 0
// update the database
if err := database.SaveRepo(repo); err != nil {
t.Error(err)
}
// get the updated repo
updatedRepo, err := database.GetRepo(1)
if err != nil {
t.Error(err)
}
if updatedRepo.Slug != repo.Slug {
t.Errorf("Exepected Slug %s, got %s", updatedRepo.Slug, repo.Slug)
}
if updatedRepo.Host != repo.Host {
t.Errorf("Exepected Host %s, got %s", updatedRepo.Host, repo.Host)
}
if updatedRepo.Private != repo.Private {
t.Errorf("Exepected Private %v, got %v", updatedRepo.Private, repo.Private)
}
if updatedRepo.Disabled != repo.Disabled {
t.Errorf("Exepected Private %v, got %v", updatedRepo.Disabled, repo.Disabled)
}
if updatedRepo.SCM != repo.SCM {
t.Errorf("Exepected Type %s, got %s", true, repo.SCM)
}
if updatedRepo.URL != repo.URL {
t.Errorf("Exepected URL %s, got %s", updatedRepo.URL, repo.URL)
}
if updatedRepo.Username != repo.Username {
t.Errorf("Exepected Username %s, got %s", updatedRepo.Username, repo.Username)
}
if updatedRepo.Password != repo.Password {
t.Errorf("Exepected Password %s, got %s", updatedRepo.Password, repo.Password)
}
if updatedRepo.TeamID != repo.TeamID {
t.Errorf("Exepected TeamID %d, got %d", updatedRepo.TeamID, repo.TeamID)
}
}
func TestDeleteRepo(t *testing.T) {
Setup()
defer Teardown()
if err := database.DeleteRepo(1); err != nil {
t.Error(err)
}
// try to get the deleted row
_, err := database.GetRepo(1)
if err == nil {
t.Fail()
}
}
/*
func TestListRepos(t *testing.T) {
Setup()
defer Teardown()
// repos for user_id = 1
repos, err := database.ListRepos(1)
if err != nil {
t.Error(err)
}
// verify user count
if len(repos) != 2 {
t.Errorf("Exepected %d repos in database, got %d", 2, len(repos))
return
}
// get the second repo in the list and verify
// fields are being populated correctly
// NOTE: we get the 2nd repo due to sorting
repo := repos[1]
if repo.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.ID)
}
if repo.Name != "github.com/drone/drone" {
t.Errorf("Exepected Name %s, got %s", "github.com/drone/drone", repo.Name)
}
if repo.Host != "github.com" {
t.Errorf("Exepected Host %s, got %s", "github.com", repo.Host)
}
if repo.Owner != "drone" {
t.Errorf("Exepected Owner %s, got %s", "drone", repo.Owner)
}
if repo.Slug != "drone" {
t.Errorf("Exepected Slug %s, got %s", "drone", repo.Slug)
}
if repo.Private != true {
t.Errorf("Exepected Private %v, got %v", true, repo.Private)
}
if repo.Disabled != false {
t.Errorf("Exepected Private %v, got %v", false, repo.Disabled)
}
if repo.SCM != "git" {
t.Errorf("Exepected Type %s, got %s", "git", repo.SCM)
}
if repo.URL != "git@github.com:drone/drone.git" {
t.Errorf("Exepected URL %s, got %s", "git@github.com:drone/drone.git", repo.URL)
}
if repo.Username != "no username" {
t.Errorf("Exepected Username %s, got %s", "no username", repo.Username)
}
if repo.Password != "no password" {
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
}
if repo.PublicKey != "public key" {
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
}
if repo.PrivateKey != "private key" {
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
}
if repo.UserID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.UserID)
}
if repo.TeamID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.TeamID)
}
}
*/
func TestListReposTeam(t *testing.T) {
Setup()
defer Teardown()
// repos for team_id = 1
repos, err := database.ListReposTeam(1)
if err != nil {
t.Error(err)
}
// verify user count
if len(repos) != 2 {
t.Errorf("Exepected %d repos in database, got %d", 2, len(repos))
return
}
// get the second repo in the list and verify
// fields are being populated correctly
// NOTE: we get the 2nd repo due to sorting
repo := repos[1]
if repo.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.ID)
}
if repo.Slug != "github.com/drone/drone" {
t.Errorf("Exepected Slug %s, got %s", "github.com/drone/drone", repo.Slug)
}
if repo.Host != "github.com" {
t.Errorf("Exepected Host %s, got %s", "github.com", repo.Host)
}
if repo.Owner != "drone" {
t.Errorf("Exepected Owner %s, got %s", "drone", repo.Owner)
}
if repo.Name != "drone" {
t.Errorf("Exepected Name %s, got %s", "drone", repo.Name)
}
if repo.Private != true {
t.Errorf("Exepected Private %v, got %v", true, repo.Private)
}
if repo.Disabled != false {
t.Errorf("Exepected Private %v, got %v", false, repo.Disabled)
}
if repo.SCM != "git" {
t.Errorf("Exepected Type %s, got %s", "git", repo.SCM)
}
if repo.URL != "git@github.com:drone/drone.git" {
t.Errorf("Exepected URL %s, got %s", "git@github.com:drone/drone.git", repo.URL)
}
if repo.Username != "no username" {
t.Errorf("Exepected Username %s, got %s", "no username", repo.Username)
}
if repo.Password != "no password" {
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
}
if repo.PublicKey != "public key" {
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
}
if repo.PrivateKey != "private key" {
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
}
if repo.UserID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.UserID)
}
if repo.TeamID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, repo.TeamID)
}
}

View File

@@ -0,0 +1,63 @@
package database
import (
"testing"
"github.com/drone/drone/pkg/database"
)
func TestGetSettings(t *testing.T) {
Setup()
defer Teardown()
// even though no settings exist yet, we should
// not see an error since we supress the msg
settings, err := database.GetSettings()
//if err != nil {
// t.Error(err)
//}
// add some settings
//settings := &modelSettings{}
settings.Scheme = "https"
settings.Domain = "foo.com"
settings.BitbucketKey = "bitbucketkey"
settings.BitbucketSecret = "bitbucketsecret"
settings.GitHubKey = "githubkey"
settings.GitHubSecret = "githubsecret"
settings.SmtpAddress = "noreply@foo.bar"
settings.SmtpServer = "0.0.0.0"
settings.SmtpUsername = "username"
settings.SmtpPassword = "password"
// save the updated settings
if err := database.SaveSettings(settings); err != nil {
t.Error(err)
}
// re-retrieve the settings post-save
settings, err = database.GetSettings()
if err != nil {
t.Error(err)
}
if settings.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, settings.ID)
}
if settings.Scheme != "https" {
t.Errorf("Exepected Scheme %s, got %s", "https", settings.Scheme)
}
if settings.Domain != "foo.com" {
t.Errorf("Exepected Domain %s, got %s", "foo.com", settings.Domain)
}
// Verify caching works and is threadsafe
settingsA, _ := database.GetSettings()
settingsB, _ := database.GetSettings()
settingsA.Domain = "foo.bar.baz"
if settingsA.Domain == settingsB.Domain {
t.Errorf("Exepected Domain ThreadSafe and unchanged")
}
}

View File

@@ -0,0 +1,169 @@
package database
import (
"testing"
"github.com/drone/drone/pkg/database"
)
// TODO unit test to verify unique constraint on Member.UserID and Member.TeamID
// TestGetTeam tests the ability to retrieve a Team
// from the database by Unique ID.
func TestGetTeam(t *testing.T) {
Setup()
defer Teardown()
team, err := database.GetTeam(1)
if err != nil {
t.Error(err)
}
if team.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, team.ID)
}
if team.Name != "Drone" {
t.Errorf("Exepected Name %s, got %s", "Drone", team.Name)
}
if team.Slug != "drone" {
t.Errorf("Exepected Slug %s, got %s", "drone", team.Slug)
}
if team.Email != "support@drone.io" {
t.Errorf("Exepected Email %s, got %s", "brad@drone.io", team.Email)
}
if team.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", team.Gravatar)
}
}
// TestGetTeamName tests the ability to retrieve a Team
// from the database by Unique Team Name (aka Slug).
func TestGetTeamSlug(t *testing.T) {
Setup()
defer Teardown()
team, err := database.GetTeamSlug("drone")
if err != nil {
t.Error(err)
}
if team.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, team.ID)
}
if team.Name != "Drone" {
t.Errorf("Exepected Name %s, got %s", "Drone", team.Name)
}
if team.Slug != "drone" {
t.Errorf("Exepected Slug %s, got %s", "drone", team.Slug)
}
if team.Email != "support@drone.io" {
t.Errorf("Exepected Email %s, got %s", "brad@drone.io", team.Email)
}
if team.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", team.Gravatar)
}
}
// TestUpdateTeam tests the ability to updatee an
// existing Team in the database.
func TestUpdateTeam(t *testing.T) {
Setup()
defer Teardown()
// get the user we plan to update
team, err := database.GetTeam(1)
if err != nil {
t.Error(err)
}
// update fields
team.Email = "brad@drone.io"
team.Gravatar = "61024896f291303615bcd4f7a0dcfb74"
// update the database
if err := database.SaveTeam(team); err != nil {
t.Error(err)
}
// get the updated team
updatedTeam, err := database.GetTeam(1)
if err != nil {
t.Error(err)
}
// verify the updated fields
if team.Email != updatedTeam.Email {
t.Errorf("Exepected Email %s, got %s", team.Email, updatedTeam.Email)
}
if team.Gravatar != updatedTeam.Gravatar {
t.Errorf("Exepected Gravatar %s, got %s", team.Gravatar, updatedTeam.Gravatar)
}
}
// Test the ability to delete a Team.
func TestDeleteTeam(t *testing.T) {
Setup()
defer Teardown()
// get the team we plan to update
if err := database.DeleteTeam(1); err != nil {
t.Error(err)
}
// now try to get the team from the database
_, err := database.GetTeam(1)
if err == nil {
t.Fail()
}
}
// Test the ability to get a list of Teams
// to which a User belongs.
func TestListTeam(t *testing.T) {
Setup()
defer Teardown()
teams, err := database.ListTeams(1)
if err != nil {
t.Error(err)
}
// verify team count
if len(teams) != 3 {
t.Errorf("Exepected %d teams in database, got %d", 3, len(teams))
return
}
// get the first user in the list and verify
// fields are being populated correctly
team := teams[0]
if team.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, team.ID)
}
if team.Name != "Drone" {
t.Errorf("Exepected Name %s, got %s", "Drone", team.Name)
}
if team.Slug != "drone" {
t.Errorf("Exepected Slug %s, got %s", "drone", team.Slug)
}
if team.Email != "support@drone.io" {
t.Errorf("Exepected Email %s, got %s", "brad@drone.io", team.Email)
}
if team.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", team.Gravatar)
}
}

View File

@@ -0,0 +1,207 @@
package database
import (
"crypto/aes"
"database/sql"
"log"
"github.com/drone/drone/pkg/database"
"github.com/drone/drone/pkg/database/encrypt"
. "github.com/drone/drone/pkg/model"
_ "github.com/mattn/go-sqlite3"
"github.com/russross/meddler"
)
// in-memory database used for
// unit testing purposes.
var db *sql.DB
func init() {
// create a cipher for ecnrypting and decrypting
// database fields
cipher, err := aes.NewCipher([]byte("38B241096B8DA08131563770F4CDDFAC"))
if err != nil {
log.Fatal(err)
}
// register function with meddler to encrypt and
// decrypt database fields.
meddler.Register("gobencrypt", &encrypt.EncryptedField{cipher})
// notify meddler that we are working with sqlite
meddler.Default = meddler.SQLite
}
func Setup() {
// create an in-memory database
db, _ = sql.Open("sqlite3", ":memory:")
// make sure all the tables and indexes are created
database.Set(db)
// create dummy user data
user1 := User{
Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS",
Name: "Brad Rydzewski",
Email: "brad.rydzewski@gmail.com",
Gravatar: "8c58a0be77ee441bb8f8595b7f1b4e87",
Token: "123",
Admin: true}
user2 := User{
Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS",
Name: "Thomas Burke",
Email: "cavepig@gmail.com",
Gravatar: "c62f7126273f7fa786274274a5dec8ce",
Token: "456",
Admin: false}
user3 := User{
Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS",
Name: "Carlos Morales",
Email: "ytsejammer@gmail.com",
Gravatar: "c2180a539620d90d68eaeb848364f1c2",
Token: "789",
Admin: false}
database.SaveUser(&user1)
database.SaveUser(&user2)
database.SaveUser(&user3)
// create dummy team data
team1 := Team{
Slug: "drone",
Name: "Drone",
Email: "support@drone.io",
Gravatar: "8c58a0be77ee441bb8f8595b7f1b4e87"}
team2 := Team{
Slug: "github",
Name: "Github",
Email: "support@github.com",
Gravatar: "61024896f291303615bcd4f7a0dcfb74"}
team3 := Team{
Slug: "golang",
Name: "Golang",
Email: "support@golang.org",
Gravatar: "991695cc770c6b8354b68cd18c280b95"}
database.SaveTeam(&team1)
database.SaveTeam(&team2)
database.SaveTeam(&team3)
// create team membership data
database.SaveMember(user1.ID, team1.ID, RoleOwner)
database.SaveMember(user2.ID, team1.ID, RoleAdmin)
database.SaveMember(user3.ID, team1.ID, RoleWrite)
database.SaveMember(user1.ID, team2.ID, RoleOwner)
database.SaveMember(user2.ID, team2.ID, RoleAdmin)
database.SaveMember(user3.ID, team2.ID, RoleWrite)
database.SaveMember(user1.ID, team3.ID, RoleOwner)
// create dummy repo data
repo1 := Repo{
Slug: "github.com/drone/drone",
Host: "github.com",
Owner: "drone",
Name: "drone",
Private: true,
Disabled: false,
SCM: "git",
URL: "git@github.com:drone/drone.git",
Username: "no username",
Password: "no password",
PublicKey: "public key",
PrivateKey: "private key",
UserID: user1.ID,
TeamID: team1.ID,
}
repo2 := Repo{
Slug: "bitbucket.org/drone/test",
Host: "bitbucket.org",
Owner: "drone",
Name: "test",
Private: false,
Disabled: false,
SCM: "hg",
URL: "https://bitbucket.org/drone/test",
Username: "no username",
Password: "no password",
PublicKey: "public key",
PrivateKey: "private key",
UserID: user1.ID,
TeamID: team1.ID,
}
repo3 := Repo{
Slug: "bitbucket.org/brydzewski/test",
Host: "bitbucket.org",
Owner: "brydzewski",
Name: "test",
Private: false,
Disabled: false,
SCM: "hg",
URL: "https://bitbucket.org/brydzewski/test",
Username: "no username",
Password: "no password",
PublicKey: "public key",
PrivateKey: "private key",
UserID: user2.ID,
}
database.SaveRepo(&repo1)
database.SaveRepo(&repo2)
database.SaveRepo(&repo3)
commit1 := Commit{
RepoID: repo1.ID,
Status: "Success",
Hash: "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608",
Branch: "master",
Author: user1.Email,
Gravatar: user1.Gravatar,
Message: "commit message",
}
commit2 := Commit{
RepoID: repo1.ID,
Status: "Failure",
Hash: "0eb2fa13e9f4139e803b6ad37831708d4786c74a",
Branch: "master",
Author: user1.Email,
Gravatar: user1.Gravatar,
Message: "commit message",
}
commit3 := Commit{
RepoID: repo1.ID,
Status: "Failure",
Hash: "60a7fe87ccf01d0152e53242528399e05acaf047",
Branch: "dev",
Author: user1.Email,
Gravatar: user1.Gravatar,
Message: "commit message",
}
commit4 := Commit{
RepoID: repo2.ID,
Status: "Success",
Hash: "a4078d1e9a0842cdd214adbf0512578799a4f2ba",
Branch: "master",
Author: user1.Email,
Gravatar: user1.Gravatar,
Message: "commit message",
}
// create dummy commit data
database.SaveCommit(&commit1)
database.SaveCommit(&commit2)
database.SaveCommit(&commit3)
database.SaveCommit(&commit4)
// create dummy build data
database.SaveBuild(&Build{CommitID: commit1.ID, Slug: "node_0.10", Status: "Success", Duration: 60})
database.SaveBuild(&Build{CommitID: commit1.ID, Slug: "node_0.09", Status: "Success", Duration: 70})
database.SaveBuild(&Build{CommitID: commit2.ID, Slug: "node_0.10", Status: "Success", Duration: 10})
database.SaveBuild(&Build{CommitID: commit2.ID, Slug: "node_0.09", Status: "Failure", Duration: 65})
database.SaveBuild(&Build{CommitID: commit3.ID, Slug: "node_0.10", Status: "Failure", Duration: 50})
database.SaveBuild(&Build{CommitID: commit3.ID, Slug: "node_0.09", Status: "Failure", Duration: 55})
}
func Teardown() {
db.Close()
}

View File

@@ -0,0 +1,169 @@
package database
import (
"testing"
"github.com/drone/drone/pkg/database"
)
// TODO unit test to verify unique constraint on User.Username
// TODO unit test to verify unique constraint on User.Email
// TestGetUser tests the ability to retrieve a User
// from the database by Unique ID.
func TestGetUser(t *testing.T) {
Setup()
defer Teardown()
u, err := database.GetUser(1)
if err != nil {
t.Error(err)
}
if u.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, u.ID)
}
if u.Password != "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS" {
t.Errorf("Exepected Password %s, got %s", "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", u.Password)
}
if u.Name != "Brad Rydzewski" {
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", u.Name)
}
if u.Email != "brad.rydzewski@gmail.com" {
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", u.Email)
}
if u.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", u.Gravatar)
}
}
// TestGetUseEmail tests the ability to retrieve a User
// from the database by Email address.
func TestGetUserEmail(t *testing.T) {
Setup()
defer Teardown()
u, err := database.GetUserEmail("brad.rydzewski@gmail.com")
if err != nil {
t.Error(err)
}
if u.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, u.ID)
}
if u.Password != "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS" {
t.Errorf("Exepected Password %s, got %s", "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", u.Password)
}
if u.Name != "Brad Rydzewski" {
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", u.Name)
}
if u.Email != "brad.rydzewski@gmail.com" {
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", u.Email)
}
if u.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", u.Gravatar)
}
}
// TestUpdateUser tests the ability to updatee an
// existing User in the database.
func TestUpdateUser(t *testing.T) {
Setup()
defer Teardown()
// get the user we plan to update
user, err := database.GetUser(1)
if err != nil {
t.Error(err)
}
// update fields
user.Email = "brad@drone.io"
user.Password = "password"
// update the database
if err := database.SaveUser(user); err != nil {
t.Error(err)
}
// get the updated user
updatedUser, err := database.GetUser(1)
if err != nil {
t.Error(err)
}
// verify the updated fields
if user.Email != updatedUser.Email {
t.Errorf("Exepected Email %s, got %s", user.Email, updatedUser.Email)
}
if user.Password != updatedUser.Password {
t.Errorf("Exepected Password %s, got %s", user.Email, updatedUser.Password)
}
}
// Deletes an existing User account.
func TestDeleteUser(t *testing.T) {
Setup()
defer Teardown()
// get the user we plan to update
if err := database.DeleteUser(1); err != nil {
t.Error(err)
}
// now try to get the user from the database
_, err := database.GetUser(1)
if err == nil {
t.Fail()
}
}
// Returns a list of all Users.
func TestListUsers(t *testing.T) {
Setup()
defer Teardown()
users, err := database.ListUsers()
if err != nil {
t.Error(err)
}
// verify user count
if len(users) != 3 {
t.Errorf("Exepected %d users in database, got %d", 3, len(users))
return
}
// get the first user in the list and verify
// fields are being populated correctly
u := users[0]
if u.ID != 1 {
t.Errorf("Exepected ID %d, got %d", 1, u.ID)
}
if u.Password != "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS" {
t.Errorf("Exepected Password %s, got %s", "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", u.Password)
}
if u.Name != "Brad Rydzewski" {
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", u.Name)
}
if u.Email != "brad.rydzewski@gmail.com" {
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", u.Email)
}
if u.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", u.Gravatar)
}
}

90
pkg/database/users.go Normal file
View File

@@ -0,0 +1,90 @@
package database
import (
"time"
. "github.com/drone/drone/pkg/model"
"github.com/russross/meddler"
)
// Name of the User table in the database
const userTable = "users"
// SQL Queries to retrieve a user by their unique database key
const userFindIdStmt = `
SELECT id, email, password, name, gravatar, created, updated, admin,
github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret
FROM users WHERE id = ?
`
// SQL Queries to retrieve a user by their email address
const userFindEmailStmt = `
SELECT id, email, password, name, gravatar, created, updated, admin,
github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret
FROM users WHERE email = ?
`
// SQL Queries to retrieve a list of all users
const userStmt = `
SELECT id, email, password, name, gravatar, created, updated, admin,
github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret
FROM users
ORDER BY name ASC
`
// Returns the User with the given ID.
func GetUser(id int64) (*User, error) {
user := User{}
err := meddler.QueryRow(db, &user, userFindIdStmt, id)
return &user, err
}
// Returns the User with the given email address.
func GetUserEmail(email string) (*User, error) {
user := User{}
err := meddler.QueryRow(db, &user, userFindEmailStmt, email)
return &user, err
}
// Returns the User Password Hash for the given
// email address.
func GetPassEmail(email string) ([]byte, error) {
user, err := GetUserEmail(email)
if err != nil {
return nil, err
}
return []byte(user.Password), nil
}
// Saves the User account.
func SaveUser(user *User) error {
if user.ID == 0 {
user.Created = time.Now().UTC()
}
user.Updated = time.Now().UTC()
return meddler.Save(db, userTable, user)
}
// Deletes an existing User account.
func DeleteUser(id int64) error {
db.Exec("DELETE FROM members WHERE user_id = ?", id)
db.Exec("DELETE FROM users WHERE id = ?", id)
// TODO delete all projects
return nil
}
// Returns a list of all Users.
func ListUsers() ([]*User, error) {
var users []*User
err := meddler.QueryAll(db, &users, userStmt)
return users, err
}
// Returns a list of Users within the specified
// range (for pagination purposes).
func ListUsersRange(limit, offset int) ([]*User, error) {
var users []*User
err := meddler.QueryAll(db, &users, userStmt)
return users, err
}