func (s *sandbox) ExtractFolder(folder string, handler engines.FileHandler) error {
	if !strings.HasSuffix(folder, "/") {
		folder += "/"
	}
	wg := sync.WaitGroup{}
	m := sync.Mutex{}
	handlerError := false
	foundFolder := false
	for p, data := range s.files {
		if strings.HasPrefix(p, folder) {
			foundFolder = true
			wg.Add(1)
			go func(p string, data []byte) {
				p = p[len(folder):] // Note: folder always ends with slash
				err := handler(p, ioext.NopCloser(bytes.NewReader(data)))
				if err != nil {
					m.Lock()
					handlerError = true
					m.Unlock()
				}
				wg.Done()
			}(p, data)
		}
	}
	wg.Wait()
	if !foundFolder {
		return engines.ErrResourceNotFound
	}
	if handlerError {
		return engines.ErrHandlerInterrupt
	}
	return nil
}
func (s *sandbox) ExtractFile(path string) (ioext.ReadSeekCloser, error) {
	data := s.files[path]
	if len(data) == 0 {
		return nil, engines.ErrResourceNotFound
	}
	return ioext.NopCloser(bytes.NewReader(data)), nil
}
func TestPutArtifact200(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello, client")
	}))
	defer ts.Close()

	err := putArtifact(ts.URL, "text/plain", ioext.NopCloser(&bytes.Reader{}), map[string]string{})
	if err != nil {
		t.Error(err)
	}
}
func TestPutArtifact400(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(404)
	}))
	defer ts.Close()

	err := putArtifact(ts.URL, "text/plain", ioext.NopCloser(&bytes.Reader{}), map[string]string{})
	if err == nil {
		t.Fail()
	}
}
func TestPutArtifact500(t *testing.T) {
	tries := 0
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if tries < 3 {
			w.WriteHeader(500)
			tries++
		} else {
			w.WriteHeader(200)
		}
	}))
	defer ts.Close()

	err := putArtifact(ts.URL, "text/plain", ioext.NopCloser(&bytes.Reader{}), map[string]string{})
	if err != nil {
		t.Error(err)
	}
}
func TestS3Artifact(t *testing.T) {

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello, client")
	}))
	defer ts.Close()

	s3resp, _ := json.Marshal(queue.S3ArtifactResponse{
		PutURL: ts.URL,
	})

	artifact := &S3Artifact{
		Name:     "public/test.txt",
		Mimetype: "text/plain",
		Stream:   ioext.NopCloser(&bytes.Reader{}),
	}

	context, mockedQueue := setupArtifactTest(artifact.Name, s3resp)

	UploadS3Artifact(*artifact, context)
	mockedQueue.AssertExpectations(t)
}
func (p *taskPlugin) createSocketsFile() error {
	debug("Uploading sockets.json")
	// Create sockets.json
	sockets := map[string]interface{}{
		"version": 2,
	}
	if p.shellURL != "" {
		sockets["shellSocketUrl"] = p.shellURL
	}
	if p.displaysURL != "" {
		sockets["displaysUrl"] = p.displaysURL
	}
	if p.displaySocketURL != "" {
		sockets["displaySocketUrl"] = p.displaySocketURL
	}
	data, _ := json.MarshalIndent(sockets, "", "  ")
	return runtime.UploadS3Artifact(runtime.S3Artifact{
		Name:     p.opts.ArtifactPrefix + "sockets.json",
		Mimetype: "application/json",
		Expires:  p.context.TaskInfo.Deadline,
		Stream:   ioext.NopCloser(bytes.NewReader(data)),
	}, p.context)
}