Skip to content

Commit

Permalink
Merge pull request #97 from ivanilves/end2end
Browse files Browse the repository at this point in the history
End2End integration testing!
  • Loading branch information
ivanilves authored Nov 11, 2017
2 parents 9402602 + 1fb95d9 commit 42da55b
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 35 deletions.
2 changes: 1 addition & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,19 +125,18 @@ CHANGED sha256:aa96c8dc3815c44d4aceaf1ee7903ce58 37c7be7a096b 2017-10-25T2

## Development

**You are very welcome to open pull requests to this repository!**
**You are very welcome to open pull requests to this repository!** :wink:

We would ask you to follow these general/common sense rules:
* Please add description (what?/why?/etc) to your pull request
* Your code should pass CI (Travis) and a pretty liberal code review
* If code adds or changes some logic, it should be covered by a unit test
To maximize our collaboration efficiency we would humbly ask you to follow these recommendations:
* Please add reasonable description (what?/why?/etc) to your pull request :exclamation:
* Your code should pass CI (Travis) and a [pretty liberal] code review :mag:
* If code adds or changes some logic, it should be covered by a unit test :neckbeard:
* Please, please, please: Put meaningful messages on your commits :pray:

### 'NORELEASE' branches and commits
We have automatic release system.

Which means every PR merge will create a new application release with a changelog generated from PR branch commits.
**NB!** Not a requirement, but a GIF included in PR description would make our world a happier place!

If you do not want to create release from your PR, make it from branch containing "NORELEASE" keyword in its name.

If you want to prevent single commit from appearing in a changelog, please start commit message from "NORELEASE".
### 'NORELEASE' branches and commits
**We have automatic release system.** Every PR merge will create a new application release with a changelog generated from PR branch commits.
For the most cases it is OK. However, if you work with things that do not need to be released (e.g. non user-facing changes), you have following options:
* If you don't want to create release from your PR, make it from branch containing "NORELEASE" keyword in its name.
* If you want to prevent single commit from appearing in a changelog, please start commit message with "NORELEASE".
42 changes: 42 additions & 0 deletions docker/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"io/ioutil"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/go-connections/nat"
"github.com/moby/moby/client"

"golang.org/x/net/context"
Expand Down Expand Up @@ -106,3 +108,43 @@ func (dc *DockerClient) Push(ref string) error {
func (dc *DockerClient) Tag(src, dst string) error {
return dc.cli.ImageTag(context.Background(), src, dst)
}

// Run runs Docker container from the image specified (like "docker run")
func (dc *DockerClient) Run(ref, name string, portSpecs []string) (string, error) {
exposedPorts, portBindings, err := nat.ParsePortSpecs(portSpecs)
if err != nil {
return "", err
}

ctx := context.Background()

if err := dc.Pull(ref); err != nil {
return "", err
}

resp, err := dc.cli.ContainerCreate(
ctx,
&container.Config{Image: ref, ExposedPorts: exposedPorts},
&container.HostConfig{PortBindings: portBindings},
nil,
name,
)
if err != nil {
return "", err
}

if err := dc.cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
return "", err
}

return resp.ID, nil
}

// ForceRemove kills & removes Docker container having the ID specified (like "docker rm -f")
func (dc *DockerClient) ForceRemove(id string) error {
return dc.cli.ContainerRemove(
context.Background(),
id,
types.ContainerRemoveOptions{Force: true},
)
}
158 changes: 136 additions & 22 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,51 +11,165 @@ package main
import (
"testing"

"math/rand"
"os"
"strconv"

"github.com/ivanilves/lstags/docker"
dockerclient "github.com/ivanilves/lstags/docker/client"
dockerconfig "github.com/ivanilves/lstags/docker/config"
"github.com/ivanilves/lstags/tag/remote"
)

const dockerHub = "registry.hub.docker.com"
//
// Here we check the ability to fetch tags from remote registry
//
func runTestForFetchTags(
t *testing.T,
repository, filter string,
username, password string,
checkTagNames []string,
) {
registry := docker.GetRegistry(repository)
repoPath := docker.GetRepoPath(repository, registry)

const dockerJSON = "./fixtures/docker/config.json"

func TestDockerHubWithPublicRepo(t *testing.T) {
const repo = "library/alpine"

tags, err := remote.FetchTags(dockerHub, repo, ".*", "", "")
tags, err := remote.FetchTags(registry, repoPath, filter, username, password)
if err != nil {
t.Fatalf("Failed to list DockerHub public repo (%s) tags: %s", repo, err.Error())
t.Fatalf(
"Failed to fetch tags (%s~/%s/) from '%s' registry: %s",
repoPath,
filter,
registry,
err.Error(),
)
}

_, defined := tags["latest"]
if !defined {
t.Fatalf("DockerHub public repo (%s) tag 'latest' not found: %#v", repo, tags)
for _, name := range checkTagNames {
_, defined := tags[name]
if !defined {
t.Fatalf(
"Tag '%s' not found in query (%s~/%s/) to '%s' registry.\nTags: %#v",
name,
repoPath,
filter,
registry,
tags,
)
}
}
}

func TestDockerHubWithPrivateRepo(t *testing.T) {
func TestFetchTags_DockerHub_PublicRepo(t *testing.T) {
runTestForFetchTags(
t,
"alpine",
"^(3.6|latest)$",
"",
"",
[]string{"3.6", "latest"},
)
}

func TestFetchTags_DockerHub_PrivateRepo(t *testing.T) {
if os.Getenv("DOCKERHUB_PRIVATE_REPO") == "" {
t.Skipf("DOCKERHUB_PRIVATE_REPO environment variable not set!")
}
if os.Getenv("DOCKERHUB_USERNAME") == "" {
t.Skipf("DOCKERHUB_USERNAME environment variable not set!")
}
if os.Getenv("DOCKERHUB_PASSWORD") == "" {
t.Skipf("DOCKERHUB_PASSWORD environment variable not set!")
}
if os.Getenv("DOCKERHUB_PRIVATE_REPO") == "" {
t.Skipf("DOCKERHUB_PRIVATE_REPO environment variable not set!")

repository := os.Getenv("DOCKERHUB_PRIVATE_REPO")
username := os.Getenv("DOCKERHUB_USERNAME")
password := os.Getenv("DOCKERHUB_PASSWORD")

runTestForFetchTags(
t,
repository,
".*",
username,
password,
[]string{"latest"},
)
}

//
// Here we check if we could:
// * Pull specified images from remote registry
// * Push them to the local registry then (ephemeral container used to run registry)
// * Check if images pushed to the local registry are present there
//
func runTestForPullPush(
t *testing.T,
srcRepository, filter string,
username, password string,
checkTagNames []string,
) {
const dockerJSON = "./fixtures/docker/config.json"
const registryImageRef = "registry:2"
const registryContainerName = "lstags-ephemeral-registry"

hostPort := strconv.Itoa(5000 + rand.Intn(1000))
localRegistry := "127.0.0.1:" + hostPort
localPortSpec := localRegistry + ":5000"

dockerConfig, err := dockerconfig.Load(dockerJSON)
if err != nil {
t.Fatal(err)
}

user := os.Getenv("DOCKERHUB_USERNAME")
pass := os.Getenv("DOCKERHUB_PASSWORD")
repo := os.Getenv("DOCKERHUB_PRIVATE_REPO")
dc, err := dockerclient.New(dockerConfig)
if err != nil {
t.Fatal(err)
}

tags, err := remote.FetchTags(dockerHub, repo, ".*", user, pass)
dc.ForceRemove(registryContainerName)

id, err := dc.Run(
registryImageRef,
registryContainerName,
[]string{localPortSpec},
)
if err != nil {
t.Fatalf("Failed to list DockerHub private repo (%s) tags: %s", repo, err.Error())
t.Fatal(err)
}

_, defined := tags["latest"]
if !defined {
t.Fatalf("DockerHub private repo (%s) tag 'latest' not found: %#v", repo, tags)
srcRegistry := docker.GetRegistry(srcRepository)
srcRepoPath := docker.GetRepoPath(srcRepository, srcRegistry)
dstRepoPath := "lstags/" + srcRepoPath
dstRepository := localRegistry + "/" + dstRepoPath

for _, name := range checkTagNames {
src := srcRepository + ":" + name
dst := dstRepository + ":" + name

if err := dc.Pull(src); err != nil {
t.Fatal(err)
}

if err := dc.Tag(src, dst); err != nil {
t.Fatal(err)
}

if err := dc.Push(dst); err != nil {
t.Fatal(err)
}
}

runTestForFetchTags(
t,
dstRepository,
".*",
"",
"",
checkTagNames,
)

dc.ForceRemove(id)
}

func TestPullPush_DockerHub_PublicRegistry(t *testing.T) {
runTestForPullPush(t, "alpine", ".*", "", "", []string{"3.6", "latest"})
}

0 comments on commit 42da55b

Please sign in to comment.