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 }
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()) } }
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") }
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()) }
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)) } } }
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()) }
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()) }
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) } }
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 }
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()) }
func TestNewEnvSelector(t *testing.T) { assert.Panics(t, func() { NewEnvSelector(nil) }) assert.NotPanics(t, func() { NewEnvSelector(config.ProviderConfigFromMap(map[string]string{})) }) }
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]) } }