github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/e2e/compatibility_test.go (about)

     1  package e2e
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"os"
    10  	"path/filepath"
    11  	"regexp"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/opencontainers/go-digest"
    17  
    18  	"gotest.tools/assert"
    19  	"k8s.io/apimachinery/pkg/util/wait"
    20  
    21  	"gotest.tools/fs"
    22  )
    23  
    24  const (
    25  	pollTimeout = 30 * time.Second
    26  )
    27  
    28  func loadAndTagImage(info dindSwarmAndRegistryInfo, tmpDir *fs.Dir, tag string, url string) error {
    29  	err := downloadImageTarball(tmpDir.Join("image.tar"), url)
    30  	if err != nil {
    31  		return err
    32  	}
    33  
    34  	digest := ""
    35  	combined := info.dockerCmd("load", "-q", "-i", tmpDir.Join("image.tar"))
    36  	for _, line := range strings.Split(combined, "\n") {
    37  		if strings.Contains(line, "sha256:") {
    38  			digest = strings.Split(line, "sha256:")[1]
    39  		}
    40  	}
    41  	if digest == "" {
    42  		return errors.New("Image digest not found in docker load's stdout")
    43  	}
    44  
    45  	digest = strings.Trim(digest, " \r\n")
    46  	info.dockerCmd("tag", digest, tag)
    47  
    48  	return nil
    49  }
    50  
    51  func downloadImageTarball(filepath string, url string) error {
    52  	client := http.Client{Timeout: time.Minute * 1}
    53  	res, err := client.Get(url)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	defer res.Body.Close()
    58  
    59  	// Create the file
    60  	out, err := os.Create(filepath)
    61  	if err != nil {
    62  		return err
    63  	}
    64  	defer out.Close()
    65  	// Write the body to file
    66  	_, err = io.Copy(out, res.Body)
    67  	return err
    68  }
    69  
    70  func TestBackwardsCompatibilityV1(t *testing.T) {
    71  	runWithDindSwarmAndRegistry(t, func(info dindSwarmAndRegistryInfo) {
    72  		appName := "app-e2e"
    73  
    74  		data, err := ioutil.ReadFile(filepath.Join("testdata", "compatibility", "bundle-v0.9.0.json"))
    75  		assert.NilError(t, err)
    76  		// update bundle
    77  		dg := digest.SHA256.FromBytes(data)
    78  		bundleDir := filepath.Join(info.configDir, "app", "bundles", "contents", dg.Algorithm().String(), dg.Encoded())
    79  		assert.NilError(t, os.MkdirAll(bundleDir, os.FileMode(0777)))
    80  		assert.NilError(t, ioutil.WriteFile(filepath.Join(bundleDir, "bundle.json"), data, os.FileMode(0644)))
    81  		metadata := filepath.Join(info.configDir, "app", "bundles", "repositories.json")
    82  		json := fmt.Sprintf("{\"Repositories\":{\"app-e2e\":{\"app-e2e:v0.9.0\":\"%s\"}}}", dg.String())
    83  		assert.NilError(t, ioutil.WriteFile(metadata, []byte(json), 0777))
    84  
    85  		// load images build with an old Docker App version
    86  		assert.NilError(t, loadAndTagImage(info, info.tmpDir, "app-e2e:0.1.0-invoc", "https://github.com/docker/app-e2e/raw/master/images/v0.9.0/app-e2e-invoc.tar"))
    87  		assert.NilError(t, loadAndTagImage(info, info.tmpDir, "app-e2e/backend", "https://github.com/docker/app-e2e/raw/master/images/v0.9.0/backend.tar"))
    88  		assert.NilError(t, loadAndTagImage(info, info.tmpDir, "app-e2e/frontend", "https://github.com/docker/app-e2e/raw/master/images/v0.9.0/frontend.tar"))
    89  
    90  		// list images
    91  		output := info.dockerCmd("app", "image", "ls")
    92  		checkContains(t, output, []string{appName})
    93  		// inspect bundle
    94  		output = info.dockerCmd("app", "image", "inspect", "app-e2e:v0.9.0", "--pretty")
    95  		checkContains(t, output,
    96  			[]string{
    97  				`name:\s+app-e2e`,
    98  				`backend\s+1\s+app-e2e/backend`,
    99  				`frontend\s+1\s+8080\s+app-e2e/frontend`,
   100  				`ports.frontend\s+8080`,
   101  			})
   102  
   103  		// render bundle
   104  		output = info.dockerCmd("app", "image", "render", "app-e2e:v0.9.0")
   105  		checkContains(t, output,
   106  			[]string{
   107  				"image: app-e2e/frontend",
   108  				"image: app-e2e/backend",
   109  				"published: 8080",
   110  				"target: 80",
   111  			})
   112  
   113  		// Install app
   114  		output = info.dockerCmd("app", "run", "app-e2e:v0.9.0", "--name", appName)
   115  		checkContains(t, output,
   116  			[]string{
   117  				fmt.Sprintf("Creating service %s_backend", appName),
   118  				fmt.Sprintf("Creating service %s_frontend", appName),
   119  				fmt.Sprintf("Creating network %s_default", appName),
   120  			})
   121  
   122  		// Status check -- poll app list
   123  		checkStatus := func(lastAction string) {
   124  			err = wait.Poll(2*time.Second, pollTimeout, func() (bool, error) {
   125  				output = info.dockerCmd("app", "ls")
   126  				expectedLines := []string{
   127  					`RUNNING APP\s+APP NAME\s+SERVICES\s+LAST ACTION\s+RESULT\s+CREATED\s+MODIFIED\s+REFERENCE`,
   128  					fmt.Sprintf(`%s\s+%s \(0.1.0\)\s+2/2\s+%s\s+success\s+.+second[s]?\sago\s+.+second[s]?\sago\s+`, appName, appName, lastAction),
   129  				}
   130  				matches := true
   131  				for _, expected := range expectedLines {
   132  					exp := regexp.MustCompile(expected)
   133  					matches = matches && exp.MatchString(output)
   134  				}
   135  				return matches, nil
   136  			})
   137  			assert.NilError(t, err)
   138  		}
   139  
   140  		queryService := func(port string) {
   141  			err = wait.Poll(2*time.Second, pollTimeout, func() (bool, error) {
   142  				// Check the frontend service responds
   143  				url := `http://localhost:` + port
   144  				output = info.execCmd("/usr/bin/wget", "-O", "-", url)
   145  				return strings.Contains(output, `Hi there, I love Docker!`), nil
   146  			})
   147  			output = ""
   148  			if err != nil {
   149  				output = info.dockerCmd("stack", "ps", appName)
   150  			}
   151  			assert.NilError(t, err, output)
   152  		}
   153  
   154  		// Check status on install
   155  		checkStatus("install")
   156  
   157  		// query deployed service
   158  		queryService("8080")
   159  
   160  		// Inspect app
   161  		output = info.dockerCmd("app", "inspect", appName, "--pretty")
   162  		checkContains(t, output,
   163  			[]string{
   164  				"Running App:",
   165  				fmt.Sprintf("Name: %s", appName),
   166  				"Result: success",
   167  				`ports.frontend: "8080"`,
   168  			})
   169  
   170  		// Update the application, changing the port
   171  		output = info.dockerCmd("app", "update", appName, "--set", "ports.frontend=8081")
   172  		checkContains(t, output,
   173  			[]string{
   174  				fmt.Sprintf("Updating service %s_backend", appName),
   175  				fmt.Sprintf("Updating service %s_frontend", appName),
   176  			})
   177  
   178  		// check status on upgrade
   179  		checkStatus("upgrade")
   180  
   181  		// Check the frontend service responds on the new port
   182  		queryService("8081")
   183  
   184  		// Uninstall the application
   185  		output = info.dockerCmd("app", "rm", appName)
   186  		checkContains(t, output,
   187  			[]string{
   188  				fmt.Sprintf("Removing service %s_backend", appName),
   189  				fmt.Sprintf("Removing service %s_frontend", appName),
   190  				fmt.Sprintf("Removing network %s_default", appName),
   191  			})
   192  	})
   193  }