예제 #1
0
func TestBlueBoxStartWithCreateError(t *testing.T) {
	blueboxTestSetup(t, config.ProviderConfigFromMap(map[string]string{
		"CUSTOMER_ID":          "customer_id",
		"API_KEY":              "api_key",
		"LOCATION_ID":          "location_id",
		"PRODUCT_ID":           "product_id",
		"IPV6_ONLY":            "true",
		"LANGUAGE_MAP_CLOJURE": "jvm",
	}))
	defer blueboxTestTeardown()

	now := time.Now()
	jsonNow, _ := now.MarshalText()
	output := `[
		{"id": "ruby-template-id", "description": "travis-ruby-2015-07-07-00-00-a0b1c2d", "public": false, "created": "%s"},
		{"id": "jvm-template-id", "description": "travis-jvm-2015-07-07-00-00-a0b1c2d", "public": false, "created": "%s"}
	]`
	blueboxMux.HandleFunc("/api/block_templates.json", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, fmt.Sprintf(output, jsonNow, jsonNow))
	})

	blueboxMux.HandleFunc("/api/blocks.json", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, `{"error": "foobar"}`)
	})

	instance, err := blueboxProvider.Start(context.TODO(), &StartAttributes{Language: "clojure", Group: "dev"})
	if err == nil {
		t.Error("provider.Start() did not return error, but was expected to")
	}

	if instance != nil {
		t.Errorf("expected instance to be nil, but was %+v", instance)
	}
}
func setupStepOpenLogWriter() (*stepOpenLogWriter, multistep.StateBag) {
	s := &stepOpenLogWriter{logTimeout: time.Second, maxLogLength: 4}

	bp, _ := backend.NewBackendProvider("fake", config.ProviderConfigFromMap(map[string]string{}))
	ctx := gocontext.TODO()
	instance, _ := bp.Start(ctx, nil)

	job := &fakeJob{
		payload: &JobPayload{
			Type: "job:test",
			Job: JobJobPayload{
				ID:     2,
				Number: "3.1",
			},
			Build: BuildPayload{
				ID:     1,
				Number: "3",
			},
			Repository: RepositoryPayload{
				ID:   4,
				Slug: "green-eggs/ham",
			},
			UUID:     "foo-bar",
			Config:   map[string]interface{}{},
			Timeouts: TimeoutsPayload{},
		},
	}

	state := &multistep.BasicStateBag{}
	state.Put("ctx", ctx)
	state.Put("buildJob", job)
	state.Put("instance", instance)

	return s, state
}
예제 #3
0
func TestDockerStart(t *testing.T) {
	dockerTestSetup(t, config.ProviderConfigFromMap(map[string]string{}))
	defer dockerTestTeardown()

	// The client expects this to be sufficiently long
	containerId := "f2e475c0ee1825418a3d4661d39d28bee478f4190d46e1a3984b73ea175c20c3"

	imagesList := `[
		{"Created":1423149832,"Id":"fc24f3225c15b08f8d9f70c1f7148d7fcbf4b41c3acce4b7da25af9371b90501","Labels":null,"ParentId":"2b412eda4314d97ff8a90d2f8c1b65677399723d6ecc4950f4e1247a5c2193c0","RepoDigests":[],"RepoTags":["quay.io/travisci/travis-ruby:latest","travis:ruby","travis:default"],"Size":729301088,"VirtualSize":4808391658},
		{"Created":1423149832,"Id":"08a0d98600afe9d0ca4ca509b1829868cea39dcc75dea1f8dde0dc6325389b45","Labels":null,"ParentId":"2b412eda4314d97ff8a90d2f8c1b65677399723d6ecc4950f4e1247a5c2193c0","RepoDigests":[],"RepoTags":["quay.io/travisci/travis-go:latest","travis:go"],"Size":729301088,"VirtualSize":4808391658},
		{"Created":1423150056,"Id":"570c738990e5859f3b78036f0fb6822fc54dc252f83cdd6d2127e3c1717bbbfd","Labels":null,"ParentId":"2b412eda4314d97ff8a90d2f8c1b65677399723d6ecc4950f4e1247a5c2193c0","RepoDigests":[],"RepoTags":["quay.io/travisci/travis-jvm:latest","travis:java","travis:jvm","travis:clojure","travis:groovy","travis:scala"],"Size":1092914295,"VirtualSize":5172004865}
	]`
	dockerTestMux.HandleFunc("/images/json", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, imagesList)
	})

	containerCreated := fmt.Sprintf(`{"Id": "%s","Warnings":null}`, containerId)
	dockerTestMux.HandleFunc("/containers/create", func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		reqBody, _ := ioutil.ReadAll(r.Body)
		var req containerCreateRequest
		err := json.Unmarshal(reqBody, &req)
		if err != nil {
			t.Errorf("Error decoding docker client container create request: %s", err.Error())
			w.WriteHeader(400)
		} else {
			fmt.Fprintf(w, containerCreated)
		}
	})

	dockerTestMux.HandleFunc(fmt.Sprintf("/containers/%s/start", containerId), func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(204)
	})

	containerStatus := docker.Container{
		ID: containerId,
		State: docker.State{
			Running: true,
		},
	}
	dockerTestMux.HandleFunc(fmt.Sprintf("/containers/%s/json", containerId), func(w http.ResponseWriter, r *http.Request) {
		containerStatusBytes, _ := json.Marshal(containerStatus)
		w.Write(containerStatusBytes)
	})

	dockerTestMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		t.Errorf("Unexpected URL %s", r.URL.String())
		w.WriteHeader(400)
	})

	instance, err := dockerTestProvider.Start(context.TODO(), &StartAttributes{Language: "jvm", Group: ""})
	if err != nil {
		t.Errorf("provider.Start() returned error: %v", err)
	}

	if instance.ID() != "f2e475c:travis:jvm" {
		t.Errorf("Provider returned unexpected ID (\"%s\" != \"f2e475c:travis:jvm\"", instance.ID())
	}
}
예제 #4
0
func TestNewGCEProvider_RequiresProjectID(t *testing.T) {
	_, err := newGCEProvider(config.ProviderConfigFromMap(map[string]string{
		"ACCOUNT_JSON": "{}",
	}))

	if !assert.NotNil(t, err) {
		t.Fatal()
	}

	assert.Equal(t, err.Error(), "missing PROJECT_ID")
}
예제 #5
0
func TestNewGCEProvider_RequiresSSHKeyPath(t *testing.T) {
	_, err := newGCEProvider(config.ProviderConfigFromMap(map[string]string{
		"ACCOUNT_JSON": "{}",
		"PROJECT_ID":   "foo",
	}))

	if !assert.NotNil(t, err) {
		t.Fatal()
	}

	assert.Regexp(t, "missing SSH_KEY_PATH", err.Error())
}
예제 #6
0
func TestEnvSelector_Select(t *testing.T) {
	for _, tesm := range testEnvSelectorMaps {
		es, err := NewEnvSelector(config.ProviderConfigFromMap(tesm.E))
		if err != nil {
			t.Fatal(err)
		}

		for _, tc := range tesm.O {
			actual, _ := es.Select(tc.P)
			assert.Equal(t, tc.E, actual, fmt.Sprintf("%#v %q", tc.P, tc.E))
		}
	}
}
예제 #7
0
func TestNewGCEProvider_RequiresSSHKeyPassphrase(t *testing.T) {
	cfg := config.ProviderConfigFromMap(map[string]string{
		"ACCOUNT_JSON": "{}",
		"PROJECT_ID":   "foo",
	})

	gceTestSetupSSH(t, cfg)
	cfg.Unset("SSH_KEY_PASSPHRASE")
	_, err := newGCEProvider(cfg)

	if !assert.NotNil(t, err) {
		t.Fatal()
	}

	assert.Regexp(t, "missing SSH_KEY_PASSPHRASE", err.Error())
}
예제 #8
0
func TestNewGCEProvider_RequiresCorrectSSHPassphrase(t *testing.T) {
	cfg := config.ProviderConfigFromMap(map[string]string{
		"ACCOUNT_JSON": "{}",
		"PROJECT_ID":   "foo",
	})

	gceTestSetupSSH(t, cfg)
	cfg.Set("SSH_KEY_PASSPHRASE", "nonsense nope nope")

	_, err := newGCEProvider(cfg)

	if !assert.NotNil(t, err) {
		t.Fatal()
	}

	assert.Regexp(t, "x509: decryption password incorrect", err.Error())
}
예제 #9
0
func TestBlueBoxStartWithTimeout(t *testing.T) {
	blueboxTestSetup(t, config.ProviderConfigFromMap(map[string]string{
		"CUSTOMER_ID":          "customer_id",
		"API_KEY":              "api_key",
		"LOCATION_ID":          "location_id",
		"PRODUCT_ID":           "product_id",
		"IPV6_ONLY":            "true",
		"LANGUAGE_MAP_CLOJURE": "jvm",
	}))
	defer blueboxTestTeardown()

	ctx, cancel := context.WithCancel(context.TODO())

	now := time.Now()
	jsonNow, _ := now.MarshalText()
	output := `[
		{"id": "ruby-template-id", "description": "travis-ruby-2015-07-07-00-00-a0b1c2d", "public": false, "created": "%s"},
		{"id": "jvm-template-id", "description": "travis-jvm-2015-07-07-00-00-a0b1c2d", "public": false, "created": "%s"}
	]`
	blueboxMux.HandleFunc("/api/block_templates.json", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, fmt.Sprintf(output, jsonNow, jsonNow))
	})

	blueboxMux.HandleFunc("/api/blocks.json", func(w http.ResponseWriter, r *http.Request) {
		if r.FormValue("template") != "jvm-template-id" {
			t.Errorf("Expected 'jvm-template-id', got '%s'", r.FormValue("template"))
		}
		fmt.Fprintf(w, `{"id": "block-id", "hostname": "block-id.example.com", "ips":[{"address":"192.0.2.1"}], "status": "queued"}`)
	})

	blueboxMux.HandleFunc("/api/blocks/block-id.json", func(w http.ResponseWriter, r *http.Request) {
		cancel()
		fmt.Fprintf(w, `{"id": "block-id", "hostname": "block-id.example.com", "ips":[{"address":"192.0.2.1"}], "status": "running"}`)
	})

	instance, err := blueboxProvider.Start(ctx, &StartAttributes{Language: "clojure", Group: "dev"})
	if err == nil {
		t.Error("provider.Start() did not return error, but was expected to")
	}

	if instance != nil {
		t.Errorf("expected instance to be nil, but was %+v", instance)
	}
}
예제 #10
0
func gceTestSetup(t *testing.T, cfg *config.ProviderConfig, resp *gceTestResponseMap) (*gceProvider, *http.Transport, *gceTestRequestLog) {
	if cfg == nil {
		cfg = config.ProviderConfigFromMap(map[string]string{
			"ACCOUNT_JSON": "{}",
			"PROJECT_ID":   "project_id",
		})
	}

	gceTestSetupSSH(t, cfg)

	server := gceTestSetupGCEServer(resp)
	reqs := &gceTestRequestLog{}

	gceCustomHTTPTransportLock.Lock()
	transport := &http.Transport{
		Proxy: func(req *http.Request) (*url.URL, error) {
			reqs.Add(req)

			u, err := url.Parse(server.URL)
			if err != nil {
				return nil, err
			}
			q := u.Query()
			q.Set("_orig_req_url", req.URL.String())
			u.RawQuery = q.Encode()
			return u, nil
		},
	}
	gceCustomHTTPTransport = transport

	p, err := newGCEProvider(cfg)

	gceCustomHTTPTransport = nil
	gceCustomHTTPTransportLock.Unlock()

	if err != nil {
		t.Fatal(err)
	}

	provider := p.(*gceProvider)
	return provider, transport, reqs
}
예제 #11
0
func TestNewGCEProvider_RequiresValidSSHKey(t *testing.T) {
	cfg := config.ProviderConfigFromMap(map[string]string{
		"ACCOUNT_JSON": "{}",
		"PROJECT_ID":   "foo",
	})

	gceTestSetupSSH(t, cfg)

	err := ioutil.WriteFile(cfg.Get("SSH_KEY_PATH"), []byte("\x08wat"), 0644)

	if !assert.Nil(t, err) {
		t.Fatal()
	}

	_, err = newGCEProvider(cfg)

	if !assert.NotNil(t, err) {
		t.Fatal()
	}

	assert.Regexp(t, "ssh key does not contain a valid PEM block", err.Error())
}
예제 #12
0
func TestNewEnvSelector(t *testing.T) {
	assert.Panics(t, func() { NewEnvSelector(nil) })
	assert.NotPanics(t, func() {
		NewEnvSelector(config.ProviderConfigFromMap(map[string]string{}))
	})
}
예제 #13
0
func TestProcessor(t *testing.T) {
	uuid := uuid.NewRandom()
	ctx := workerctx.FromProcessor(context.TODO(), uuid.String())

	provider, err := backend.NewBackendProvider("fake", config.ProviderConfigFromMap(map[string]string{
		"LOG_OUTPUT": "hello, world",
	}))
	if err != nil {
		t.Error(err)
	}

	generator := buildScriptGeneratorFunction(func(ctx context.Context, json *simplejson.Json) ([]byte, error) {
		return []byte("hello, world"), nil
	})

	jobChan := make(chan Job)
	canceller := &fakeCanceller{}

	processor, err := NewProcessor(ctx, "test-hostname", jobChan, provider, generator, canceller, 2*time.Second, time.Second, 3*time.Second, 4*time.Second)
	if err != nil {
		t.Error(err)
	}

	doneChan := make(chan struct{})
	go func() {
		processor.Run()
		doneChan <- struct{}{}
	}()

	job := &fakeJob{
		payload: &JobPayload{
			Type: "job:test",
			Job: JobJobPayload{
				ID:     2,
				Number: "3.1",
			},
			Build: BuildPayload{
				ID:     1,
				Number: "3",
			},
			Repository: RepositoryPayload{
				ID:   4,
				Slug: "green-eggs/ham",
			},
			UUID:     "foo-bar",
			Config:   map[string]interface{}{},
			Timeouts: TimeoutsPayload{},
		},
		startAttributes: &backend.StartAttributes{},
	}
	jobChan <- job

	processor.GracefulShutdown()
	<-doneChan

	if processor.ProcessedCount != 1 {
		t.Errorf("processor.ProcessedCount = %d, expected %d", processor.ProcessedCount, 1)
	}

	expectedEvents := []string{"received", "started", string(FinishStatePassed)}
	if !reflect.DeepEqual(expectedEvents, job.events) {
		t.Errorf("job.events = %#v, expected %#v", job.events, expectedEvents)
	}

	if canceller.subscribedIDs[0] != 2 {
		t.Errorf("canceller.subscribedIDs[0] = %d, expected 2", canceller.subscribedIDs[0])
	}
	if canceller.unsubscribedIDs[0] != 2 {
		t.Errorf("canceller.unsubscribedIDs[0] = %d, expected 2", canceller.unsubscribedIDs[0])
	}
}