gerrittest

package module
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 30, 2017 License: MIT Imports: 31 Imported by: 0

README

Gerrit Testing With Docker

Build Status codecov Go Report Card GoDoc

This project is meant to assist in testing Gerrit. It provides a docker container to run Gerrit and a Makefile with some useful helpers. Documentation is available via godoc: https://godoc.org/github.com/opalmer/gerrittest

Setup

  • Install docker
  • go install github.com/opalmer/gerrittest/cmd

Command Line Usage

Start and Stop
$ go get github.com/opalmer/gerrittest
$ cd ~/go/src/github.com/opalmer/gerrittest
$ make dep build
$ ./gerrittest start --json /tmp/gerrit.json
$ cat /tmp/gerrit.json
{
  "config": {
    "image": "opalmer/gerrittest:2.14.3",
    "port_ssh": 0,
    "port_http": 0,
    "timeout": 300000000000,
    "git": {
      "core.sshCommand": "ssh -i /tmp/gerrittest-id_rsa-706055562 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no",
      "user.email": "admin@localhost",
      "user.name": "admin"
    },
    "ssh_keys": [
      {
        "path": "/tmp/gerrittest-id_rsa-706055562",
        "generated": true,
        "default": true
      }
    ],
    "username": "admin",
    "password": "oD7BNb6YE21+7ZGEXefJtFk3HY85wKYrfiZg13H6Mg",
    "skip_setup": false,
    "cleanup_container": true
  },
  "container": {
    "http": {
      "Private": 8080,
      "port": 33511,
      "address": "localhost",
      "protocol": "tcp"
    },
    "ssh": {
      "Private": 29418,
      "port": 32791,
      "address": "127.0.0.1",
      "protocol": "tcp"
    },
    "image": "opalmer/gerrittest:2.14.3",
    "id": "6ef42639c9a40aa3a5e793b8d7fe33005e585ae1ce636671e1bb2d15fc8b1173"
  },
  "http": {
    "Private": 8080,
    "port": 33511,
    "address": "localhost",
    "protocol": "tcp"
  },
  "ssh": {
    "Private": 29418,
    "port": 32791,
    "address": "127.0.0.1",
    "protocol": "tcp"
  }
}
$ ./gerrittest stop --json /tmp/gerrit.json
Retrieving the SSH Command
$ ./gerrittest get-ssh-command --json /tmp/gerrit.json
ssh -i /tmp/gerrittest-id_rsa-706055562 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 32791 admin@127.0.0.1
Combining gerrittest, bash and curl

$ JSON="/tmp/services.json"
$ PREFIX=")]}'"
$ gerrittest start --json "$JSON"
$ USERNAME="$(jq -r ".username" "$JSON")"
$ PASSWORD="$(jq -r ".password" "$JSON")"
$ URL="http://$(jq -r ".http.address" "$JSON"):$(jq -r ".http.port" "$JSON")"
$ RAW_RESPONSE="$(curl -u $USERNAME:$PASSWORD $URL/a/accounts/self --fail --silent)"
$ RESPONSE=$(echo "$RAW_RESPONSE" | sed -e "s/^$PREFIX//")
$ echo "$RESPONSE" | jq ._account_id
1000000

Code Examples

Visit godoc.org to see code examples:

https://godoc.org/github.com/opalmer/gerrittest#pkg-examples

Testing

The gerrittest project can be tested locally. To build the container and the gerrittest command run:

$ make check

You can also skip some of the slower tests:

$ go test -v -short github.com/opalmer/gerrittest

If you're having trouble with a specific test you can enable debug logging and run that test specifically:

$ go test -gerrittest.log-level=debug -check.vv -check.f RepoTest.* github.com/opalmer/gerrittest

Documentation

Index

Examples

Constants

View Source
const (
	// VerifiedLabel is a string representing the 'Verified' label
	VerifiedLabel = "Verified"

	// CodeReviewLabel is a string representing the 'Code-Review' label
	CodeReviewLabel = "Code-Review"
)
View Source
const (
	// DefaultImageEnvironmentVar defines the environment variable NewConfig()
	// and the tests should be using to locate the default image override.
	DefaultImageEnvironmentVar = "GERRITTEST_DOCKER_IMAGE"

	// ExportedHTTPPort is the port exported by the docker container
	// where the HTTP service is running.
	ExportedHTTPPort = 8080

	// ExportedSSHPort is the port exported by the docker container
	// where the SSHPort service is running.
	ExportedSSHPort = 29418
)
View Source
const ProjectName = "gerrittest"

ProjectName is used anywhere we need a default value (temp files, default field values, etc.

Variables

View Source
var (
	// GitCommand is the command used to run git commands.
	GitCommand = "git"

	// DefaultGitCommands contains a mapping of git commands
	// to their arguments. This is used by Repository for running
	// git commands.
	DefaultGitCommands = map[string][]string{
		"status":              {"status", "--porcelain"},
		"config":              {"config", "--local"},
		"add":                 {"add", "--force"},
		"remote-add":          {"remote", "add"},
		"get-remote-url":      {"remote", "get-url"},
		"commit":              {"commit", "--allow-empty", "--message"},
		"push":                {"push", "--porcelain"},
		"last-commit-message": {"log", "-n", "1", "--format=medium"},
		"amend":               {"commit", "--amend", "--no-edit", "--allow-empty"},
	}

	// ErrRemoteDoesNotExist is returned by GetRemote if the requested
	// remote does not appear to exist.
	ErrRemoteDoesNotExist = errors.New("requested remote does not exist")

	//ErrFailedToLocateChange is returned by functions, such as Push(), that
	// expect to find a change number in the output from git.
	ErrFailedToLocateChange = errors.New("failed to locate ChangeID")

	// ErrRemoteDiffers is returned by any function that adds a remote
	// where the named remote already exists but with a different url.
	ErrRemoteDiffers = errors.New(
		"the requested remote exists but with a different url")

	// ErrNoCommits is returned by ChangeID if there are not any commits
	// to the repository yet.
	ErrNoCommits = errors.New("no commits")

	// RegexChangeID is used to match the Change-Id for a commit.
	RegexChangeID = regexp.MustCompile(`(?m)^\s+Change-Id: (I[a-f0-9]{40}).*$`)
)
View Source
var (
	// DefaultImage defines the default docker image to use in
	// NewConfig(). This may be overridden with the $GERRITTEST_DOCKER_IMAGE
	// environment variable.
	DefaultImage = "opalmer/gerrittest:2.14.4"
)
View Source
var (
	// DefaultRevision is the revision to use in the Change struct when
	// no other revision is provided.
	DefaultRevision = "current"
)

Functions

func GenerateRSAKey

func GenerateRSAKey() (*rsa.PrivateKey, error)

GenerateRSAKey will generate and return an SSH key pair.

func GetDockerImage

func GetDockerImage(image string) string

GetDockerImage returns the docker image to use to run the container. If "" is provided as the docker then we'll check $GERRITTEST_DOCKER_IMAGE first before returning the value defined in DefaultImage.

func GetSSHCommand added in v0.4.1

func GetSSHCommand(gerrit *Gerrit) (string, error)

GetSSHCommand returns a string representing the ssh command to run to access the Gerrit container over ssh.

func ReadSSHKeys

func ReadSSHKeys(path string) (ssh.PublicKey, ssh.Signer, error)

ReadSSHKeys will read the provided private key and return the public and private portions.

func WriteRSAKey

func WriteRSAKey(key *rsa.PrivateKey, file *os.File) error

WriteRSAKey will take a private key and write out the public and private portions to disk. nolint: interfacer

Types

type Change added in v0.3.0

type Change struct {
	ChangeID string
	Repo     *Repository
	// contains filtered or unexported fields
}

Change is used to interact with an manipulate a single change.

func (*Change) Abandon added in v0.3.0

func (c *Change) Abandon() (*gerrit.ChangeInfo, error)

Abandon will abandon the change.

func (*Change) Add added in v0.3.0

func (c *Change) Add(relative string, mode os.FileMode, content string) error

Add writes a file to the repository but does not commit it. The added or modified path will be staged for commit.

func (*Change) AddFileComment added in v0.3.0

func (c *Change) AddFileComment(revision string, path string, line int, comment string) (*gerrit.ReviewResult, error)

AddFileComment will apply a comment to a specific file in a specific location

func (*Change) AddTopLevelComment added in v0.3.0

func (c *Change) AddTopLevelComment(revision string, comment string) (*gerrit.ReviewResult, error)

AddTopLevelComment will a single top level comment to the current change.

func (*Change) ApplyLabel added in v0.3.0

func (c *Change) ApplyLabel(revision string, label string, value int) (*gerrit.ReviewResult, error)

ApplyLabel will apply the requested label to the current change. Examples of labels include 'Code-Review +2' or 'Verified +1'. If a specific revision is not provided then 'current' will be used.

func (*Change) Destroy added in v0.3.0

func (c *Change) Destroy() error

Destroy is responsible for removing any files on disk related to this change.

func (*Change) Push added in v0.3.0

func (c *Change) Push() error

Push pushes changes to Gerrit.

func (*Change) Remove added in v0.3.0

func (c *Change) Remove(relative string) error

Remove will remove the given relative path from the repository. If the file or directory does not exist this function does nothing. The removed path will staged for commit.

func (*Change) Submit added in v0.3.0

func (c *Change) Submit() (*gerrit.ChangeInfo, error)

Submit will submit the change. Note, this typically will only work if the change has Code-Review +2 and Verified +1 labels applied.

type Config

type Config struct {
	// Image is the name of docker image to run.
	Image string `json:"image"`

	// PortSSH is the port to expose the SSH service on.
	PortSSH uint16 `json:"port_ssh"`

	// PortHTTP is the port to expose the HTTP service on.
	PortHTTP uint16 `json:"port_http"`

	// Timeout is used to timeout commands and other contextual operations.
	Timeout time.Duration `json:"timeout"`

	// GitConfig contains key/value pairs to pass to 'git config'
	GitConfig map[string]string `json:"git"`

	// Context is used internally when starting or managing
	// containers and processes. If no context is provided then
	// context.Background() will be used.
	Context context.Context `json:"-"`

	// SSHKeys store information about one or more ssh keys.
	SSHKeys []*SSHKey `json:"ssh_keys"`

	// Username is the name of the Gerrit admin account to create. By default
	// this will be 'admin' unless otherwise specified.
	Username string `json:"username"`

	// Password is the password to create for the Gerrit admin user. If not
	// provided one will be randomly generated for you after the container
	// starts.
	Password string `json:"password"`

	// SkipSetup when true will cause the container to be started but
	// none of the final setup steps will be performed.
	SkipSetup bool `json:"skip_setup"`

	// CleanupContainer when true will cause the cleanup steps to destroy
	// the container running Gerrit. This defaults to true.
	CleanupContainer bool `json:"cleanup_container"`
}

Config is used to tell the *runner struct what setup steps to perform, where to listen for services, etc.

func NewConfig

func NewConfig() *Config

NewConfig produces a *Config struct with reasonable defaults.

type Container

type Container struct {
	Docker *dockertest.DockerClient `json:"-"`
	HTTP   *dockertest.Port         `json:"http"`
	SSH    *dockertest.Port         `json:"ssh"`
	Image  string                   `json:"image"`
	ID     string                   `json:"id"`
	// contains filtered or unexported fields
}

Container stores information about a Gerrit instance running inside of a container.

func NewContainer

func NewContainer(parent context.Context, http uint16, ssh uint16, image string) (*Container, error)

NewContainer will create a new container using dockertest and return it. If you prefer to use an existing container use one of the LoadContainer* functions instead. This function will not return until the container has started and is listening on the requested ports.

Example

You can start the Gerrit container using the NewContainer() function. In this example an random port will be used for both http and the default image will be used. This kind of setup is useful if you don't want to gerrittest to perform any setup steps for you.

container, err := NewContainer(
	context.Background(), dockertest.RandomPort, dockertest.RandomPort, "")
if err != nil {
	log.Fatal(err)
}

// Terminate the container when you're done.
if err := container.Terminate(); err != nil {
	log.Fatal(err)
}
Output:

func (*Container) Terminate

func (c *Container) Terminate() error

Terminate will terminate and remove the running container.

type CookieJar

type CookieJar struct {
	// contains filtered or unexported fields
}

CookieJar is an implementation of a cookie jar similar to http/cookiejar. This implementation is only intended for local development.

func NewCookieJar

func NewCookieJar() *CookieJar

NewCookieJar constructs and returns a *CookieJar struct.

func (*CookieJar) Cookies

func (c *CookieJar) Cookies(u *url.URL) (cookies []*http.Cookie)

Cookies returns the cookies associated with the given url.

func (*CookieJar) SetCookies

func (c *CookieJar) SetCookies(u *url.URL, cookies []*http.Cookie)

SetCookies will set cookies for the given url.

type Gerrit

type Gerrit struct {
	Config    *Config          `json:"config"`
	Container *Container       `json:"container"`
	HTTP      *HTTPClient      `json:"-"`
	HTTPPort  *dockertest.Port `json:"http"`
	SSH       *SSHClient       `json:"-"`
	SSHPort   *dockertest.Port `json:"ssh"`
	// contains filtered or unexported fields
}

Gerrit is the central struct which combines multiple components of the gerrittest project. Use New() to construct this struct.

func LoadJSON added in v0.4.1

func LoadJSON(path string) (*Gerrit, error)

LoadJSON strictly loads the json file from the provided path. It makes no attempts to verify that the docker container is running orr

func New

func New(cfg *Config) (*Gerrit, error)

New constructs and returns a *Gerrit struct after all setup steps have been completed. Once this function returns Gerrit will be running in a container, an admin user will be created and a git repository will be setup pointing at the service in the container.

func NewFromJSON

func NewFromJSON(path string) (*Gerrit, error)

NewFromJSON reads information from a json file and returns a *Gerrit struct.

func (*Gerrit) CreateChange added in v0.3.0

func (g *Gerrit) CreateChange(project string, subject string) (*Change, error)

CreateChange will return a *Change struct. If a change has already been created then that change will be returned instead of creating a new one.

Example

Once you've started the service you'll want to setup Gerrit inside the container. Running Setup.Init will cause the administrative user to be created, generate an http API password and insert a public key for ssh access.

cfg := NewConfig()
gerrit, err := New(cfg)
if err != nil {
	log.Fatal(err)
}
files := map[string]string{
	"README.md":        "# Hello",
	"scripts/foo.bash": "echo 'foo'",
}

change, err := gerrit.CreateChange("testing", "test")
if err != nil {
	log.Fatal(err)
}
defer change.Destroy() // nolint: errcheck
defer gerrit.Destroy() // nolint: errcheck

for relative, content := range files {
	if err := change.Add(relative, 0600, content); err != nil {
		log.Fatal(err)
	}
}
if err := change.Push(); err != nil {
	log.Fatal(err)
}
if _, err := change.ApplyLabel("1", CodeReviewLabel, 2); err != nil {
	log.Fatal(err)
}
if _, err := change.ApplyLabel("1", VerifiedLabel, 1); err != nil {
	log.Fatal(err)
}
if _, err := change.Submit(); err != nil {
	log.Fatal(err)
}
Output:

func (*Gerrit) Destroy

func (g *Gerrit) Destroy() error

Destroy will destroy the container and all associated resources. Custom private keys or repositories will not be cleaned up.

func (*Gerrit) WriteJSONFile

func (g *Gerrit) WriteJSONFile(path string) error

WriteJSONFile takes the current struct and writes the data to disk as json.

type HTTPClient

type HTTPClient struct {
	Prefix string
	// contains filtered or unexported fields
}

HTTPClient is a simple client for talking to Gerrit within a container. This is not intended as a replacement for go-gerrit. Instead, it's intended to get validate that Gerrit is setup correctly and then perform the final steps to get it ready for testing.

func NewHTTPClient

func NewHTTPClient(config *Config, port *dockertest.Port) (*HTTPClient, error)

NewHTTPClient takes a *Service struct and returns an *HTTPClient. No validation to ensure the service is actually running is performed.

func (*HTTPClient) Gerrit

func (h *HTTPClient) Gerrit() (*gerrit.Client, error)

Gerrit will return a *gerrit.Gerrit client. Note, the username and password must already be set and basic validation to ensure the client is setup properly is performed.

type Repository

type Repository struct {
	SSHCommand string
	Root       string
	Username   string
	// contains filtered or unexported fields
}

Repository is used to store information about an interact with a git repository. In the end, this is a thin wrapper around GitConfig commands.

func NewRepository

func NewRepository(config *Config) (*Repository, error)

NewRepository constructs and returns a *Repository struct. It will also ensure the repository is properly setup before returning.

func (*Repository) Add

func (r *Repository) Add(path string, mode os.FileMode, content []byte) error

Add is similar to Add() except it allows content to be created in addition to be added to the repo.

func (*Repository) AddOriginFromContainer added in v0.3.0

func (r *Repository) AddOriginFromContainer(container *Container, project string) error

AddOriginFromContainer adds a new remote based on the provided container.

func (*Repository) AddRemote

func (r *Repository) AddRemote(name string, uri string) error

AddRemote will add a remote with the given name so long as it does not already exist.

func (*Repository) Amend

func (r *Repository) Amend() error

Amend amends the current commit.

func (*Repository) ChangeID

func (r *Repository) ChangeID() (string, error)

ChangeID returns a string representing the change id of the last commit.

func (*Repository) Commit

func (r *Repository) Commit(message string) error

Commit will add a new commit to the repository with the given message.

func (*Repository) Destroy added in v0.3.0

func (r *Repository) Destroy() error

Destroy will remove the entire repository from disk, useful for temporary repositories. This cannot be reversed.

func (*Repository) GetRemote added in v0.3.0

func (r *Repository) GetRemote(name string) (string, error)

GetRemote will return the url for the given remote name. If the requested remote does not exist ErrRemoteDoesNotExist will be returned.

func (*Repository) Git

func (r *Repository) Git(args []string) (string, string, error)

Git runs git with the provided arguments. This also ensures the proper working path and environment are set before calling git.

func (*Repository) Push

func (r *Repository) Push(ref string) error

Push will push changes to the given remote and reference. `ref` will default to 'HEAD:refs/for/master' if not provided.

func (*Repository) Remove

func (r *Repository) Remove(path string) error

Remove removes the requested content from the repository.

func (*Repository) Status

func (r *Repository) Status() (string, error)

Status returns the current status of the repository.

type SSHClient

type SSHClient struct {
	Client *ssh.Client
	// contains filtered or unexported fields
}

SSHClient implements an SSH client for talking to Gerrit.

func NewSSHClient

func NewSSHClient(config *Config, port *dockertest.Port) (*SSHClient, error)

NewSSHClient produces an *SSHClient struct and attempts to connect to Gerrrit.

func (*SSHClient) Close

func (s *SSHClient) Close() error

Close will close the SSHPort client and session.

func (*SSHClient) Run

func (s *SSHClient) Run(command string) ([]byte, []byte, error)

Run executes a command over ssh.

func (*SSHClient) Version

func (s *SSHClient) Version() (string, error)

Version returns the current version of Gerrit.

type SSHKey added in v0.4.0

type SSHKey struct {
	Public    ssh.PublicKey `json:"-"`
	Private   ssh.Signer    `json:"-"`
	Path      string        `json:"path"`
	Generated bool          `json:"generated"`
	Default   bool          `json:"default"`
}

SSHKey contains information about an ssh key.

func LoadSSHKey added in v0.4.0

func LoadSSHKey(path string) (*SSHKey, error)

LoadSSHKey loads an SSH key from disk and returns a *SSHKey struct.

func NewSSHKey added in v0.4.0

func NewSSHKey() (*SSHKey, error)

NewSSHKey will generate and return an *SSHKey. TODO add tests

func (*SSHKey) Remove added in v0.4.0

func (s *SSHKey) Remove() error

Remove will remove the key material from disk but only if the key was generated.

func (*SSHKey) String added in v0.4.0

func (s *SSHKey) String() string

String outputs a useful string representing the struct.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL