зеркало из https://github.com/golang/build.git
204 строки
6.6 KiB
Go
204 строки
6.6 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package buildlet
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// RemoteClient is a subset of methods that can be used by a gomote client.
|
|
type RemoteClient interface {
|
|
Close() error
|
|
Exec(ctx context.Context, cmd string, opts ExecOpts) (remoteErr, execErr error)
|
|
GetTar(ctx context.Context, dir string) (io.ReadCloser, error)
|
|
ListDir(ctx context.Context, dir string, opts ListDirOpts, fn func(DirEntry)) error
|
|
Put(ctx context.Context, r io.Reader, path string, mode os.FileMode) error
|
|
PutTar(ctx context.Context, r io.Reader, dir string) error
|
|
PutTarFromURL(ctx context.Context, tarURL, dir string) error
|
|
ProxyTCP(port int) (io.ReadWriteCloser, error)
|
|
RemoteName() string
|
|
RemoveAll(ctx context.Context, paths ...string) error
|
|
WorkDir(ctx context.Context) (string, error)
|
|
}
|
|
|
|
// Client is an interface that represent the methods exposed by client. The
|
|
// fake buildlet client should be used instead of client when testing things that
|
|
// use the client interface.
|
|
// This includes a number of coordinator-internal details; users outside the
|
|
// coordinator should use RemoteClient.
|
|
type Client interface {
|
|
RemoteClient
|
|
ConnectSSH(user, authorizedPubKey string) (net.Conn, error)
|
|
IPPort() string
|
|
InstanceName() string
|
|
IsBroken() bool
|
|
MarkBroken()
|
|
Name() string
|
|
ProxyRoundTripper() http.RoundTripper
|
|
SetDescription(v string)
|
|
SetDialer(dialer func(context.Context) (net.Conn, error))
|
|
SetHTTPClient(httpClient *http.Client)
|
|
SetInstanceName(v string)
|
|
SetName(name string)
|
|
SetOnHeartbeatFailure(fn func())
|
|
Status(ctx context.Context) (Status, error)
|
|
String() string
|
|
URL() string
|
|
}
|
|
|
|
var errUnimplemented = errors.New("unimplemented function")
|
|
|
|
var _ Client = (*FakeClient)(nil)
|
|
|
|
// FakeClient is a fake buildlet client used for testing. Not all functions are implemented.
|
|
type FakeClient struct {
|
|
closeFuncs []func()
|
|
instanceName string
|
|
name string
|
|
}
|
|
|
|
// Close is a fake client closer.
|
|
func (fc *FakeClient) Close() error {
|
|
for _, f := range fc.closeFuncs {
|
|
f()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ConnectSSH connects to a fake SSH server.
|
|
func (fc *FakeClient) ConnectSSH(user, authorizedPubKey string) (net.Conn, error) {
|
|
return nil, errUnimplemented
|
|
}
|
|
|
|
// Exec fakes the execution.
|
|
func (fc *FakeClient) Exec(ctx context.Context, cmd string, opts ExecOpts) (remoteErr, execErr error) {
|
|
if cmd == "" {
|
|
return nil, errors.New("invalid command")
|
|
}
|
|
if opts.Output == nil {
|
|
return nil, nil
|
|
}
|
|
out := []byte("<this is a song that never ends>")
|
|
for it := 0; it < 3; it++ {
|
|
if n, err := opts.Output.Write(out); n != len(out) || err != nil {
|
|
return nil, fmt.Errorf("Output.Write(...) = %d, %q; want %d, no error", n, err, len(out))
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
// InstanceName gives the fake instance name.
|
|
func (fc *FakeClient) InstanceName() string { return fc.instanceName }
|
|
|
|
// GetTar gives a vake tar zipped directory.
|
|
func (fc *FakeClient) GetTar(ctx context.Context, dir string) (io.ReadCloser, error) {
|
|
r := strings.NewReader("the gopher goes to the sea and fights the kraken")
|
|
return io.NopCloser(r), nil
|
|
}
|
|
|
|
// IPPort provides a fake ip and port pair.
|
|
func (fc *FakeClient) IPPort() string { return "" }
|
|
|
|
// IsBroken returns a fake broken response.
|
|
func (fc *FakeClient) IsBroken() bool { return false }
|
|
|
|
// ListDir lists a directory on a fake buildlet.
|
|
func (fc *FakeClient) ListDir(ctx context.Context, dir string, opts ListDirOpts, fn func(DirEntry)) error {
|
|
if dir == "" || fn == nil {
|
|
return errors.New("invalid arguments")
|
|
}
|
|
var lsOutput = `drwxr-xr-x gocache/
|
|
drwxr-xr-x tmp/`
|
|
lines := strings.Split(lsOutput, "\n")
|
|
for _, line := range lines {
|
|
fn(DirEntry{Line: line})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MarkBroken marks the fake client as broken.
|
|
func (fc *FakeClient) MarkBroken() {}
|
|
|
|
// Name is the name of the fake client.
|
|
func (fc *FakeClient) Name() string { return fc.name }
|
|
|
|
// ProxyRoundTripper provides a fake proxy.
|
|
func (fc *FakeClient) ProxyRoundTripper() http.RoundTripper { return nil }
|
|
|
|
// ProxyTCP provides a fake proxy.
|
|
func (fc *FakeClient) ProxyTCP(port int) (io.ReadWriteCloser, error) { return nil, errUnimplemented }
|
|
|
|
// Put places a file on a fake buildlet.
|
|
func (fc *FakeClient) Put(ctx context.Context, r io.Reader, path string, mode os.FileMode) error {
|
|
// TODO(go.dev/issue/48742) add a file system implementation which would enable proper testing.
|
|
if path == "" {
|
|
return errors.New("invalid argument")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// PutTar fakes putting a tar zipped file on a buildldet.
|
|
func (fc *FakeClient) PutTar(ctx context.Context, r io.Reader, dir string) error {
|
|
// TODO(go.dev/issue/48742) add a file system implementation which would enable proper testing.
|
|
return errUnimplemented
|
|
}
|
|
|
|
// PutTarFromURL fakes putting a tar zipped file on a builelt.
|
|
func (fc *FakeClient) PutTarFromURL(ctx context.Context, tarURL, dir string) error {
|
|
return nil
|
|
}
|
|
|
|
// RemoteName gives the remote name of the fake buildlet.
|
|
func (fc *FakeClient) RemoteName() string { return "" }
|
|
|
|
// SetDescription sets the description on a fake client.
|
|
func (fc *FakeClient) SetDescription(v string) {}
|
|
|
|
// SetDialer sets the function that creates a new connection to the fake buildlet.
|
|
func (fc *FakeClient) SetDialer(dialer func(context.Context) (net.Conn, error)) {}
|
|
|
|
// SetInstanceName sets the GCE or EC2 instance name on a fake client.
|
|
func (fc *FakeClient) SetInstanceName(v string) {
|
|
fc.instanceName = v
|
|
}
|
|
|
|
// SetHTTPClient sets the HTTP client on a fake client.
|
|
func (fc *FakeClient) SetHTTPClient(httpClient *http.Client) {}
|
|
|
|
// SetName sets the name on a fake client.
|
|
func (fc *FakeClient) SetName(name string) {
|
|
fc.name = name
|
|
}
|
|
|
|
// SetOnHeartbeatFailure sets a function to be called when heartbeats against this fake buildlet fail.
|
|
func (fc *FakeClient) SetOnHeartbeatFailure(fn func()) {}
|
|
|
|
// Status provides a status on the fake client.
|
|
func (fc *FakeClient) Status(ctx context.Context) (Status, error) { return Status{}, errUnimplemented }
|
|
|
|
// String provides a fake string representation of the client.
|
|
func (fc *FakeClient) String() string { return "" }
|
|
|
|
// URL is the URL for a fake buildlet.
|
|
func (fc *FakeClient) URL() string { return "" }
|
|
|
|
// WorkDir is the working directory for the fake buildlet.
|
|
func (fc *FakeClient) WorkDir(ctx context.Context) (string, error) {
|
|
return "/work", nil
|
|
}
|
|
|
|
// RemoveAll deletes the provided paths, relative to the work directory for a fake buildlet.
|
|
func (fc *FakeClient) RemoveAll(ctx context.Context, paths ...string) error {
|
|
// TODO(go.dev/issue/48742) add a file system implementation which would enable proper testing.
|
|
return nil
|
|
}
|