func (fu Uploader) Copy(ctx context.Context, from, to gcs.Path) (*storage.ObjectAttrs, error) {
	if err := ctx.Err(); err != nil {
		return nil, fmt.Errorf("injected interrupt: %w", err)
	}
	u, present := fu[from]
	if !present {
		return nil, storage.ErrObjectNotExist
	}
	if err := u.Err; err != nil {
		return nil, fmt.Errorf("injected from error: %w", err)
	}
	u.Generation++
	fu[to] = u
	return u.Attrs(to), nil
}
Copy an object to the specified path
package fake
import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"sync"
	"cloud.google.com/go/storage"
	"github.com/GoogleCloudPlatform/testgrid/util/gcs"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/iterator"
)
type ConditionalClient struct {
	UploadClient
	read, write *storage.Conditions
	Lock        *sync.RWMutex
}
func (cc *ConditionalClient) check(ctx context.Context, from, to *gcs.Path) error {
	if from != nil && cc.read != nil {
		attrs, err := cc.UploadClient.Stat(ctx, *from)
		if err != nil {
			return err
		}
		if cc.read.GenerationMatch != 0 && cc.read.GenerationMatch != attrs.Generation {
			return fmt.Errorf("bad generation: %w", &googleapi.Error{
				Code: http.StatusPreconditionFailed,
			})
		}
	}
	if to != nil && cc.write != nil {
		attrs, err := cc.UploadClient.Stat(ctx, *to)
		switch {
		case err == storage.ErrObjectNotExist:
			if cc.write.GenerationMatch != 0 {
				return fmt.Errorf("bad generation: %w", &googleapi.Error{
					Code: http.StatusPreconditionFailed,
				})
			}
		case err != nil:
			return err
		case cc.write.GenerationMatch != 0 && cc.write.GenerationMatch != attrs.Generation:
			return fmt.Errorf("bad generation: %w", &googleapi.Error{
				Code: http.StatusPreconditionFailed,
			})
		}
	}
	return nil
}
func (cc *ConditionalClient) Copy(ctx context.Context, from, to gcs.Path) (*storage.ObjectAttrs, error) {
	if cc.Lock != nil {
		cc.Lock.Lock()
		defer cc.Lock.Unlock()
	}
	if err := cc.check(ctx, &from, &to); err != nil {
		return nil, err
	}
	gen := cc.Uploader[to].Generation + 1
	if _, err := cc.UploadClient.Copy(ctx, from, to); err != nil {
		return nil, err
	}
	u := cc.Uploader[to]
	u.Generation = gen
	cc.Uploader[to] = u
	return u.Attrs(to), nil
}
func (cc *ConditionalClient) Upload(ctx context.Context, path gcs.Path, buf []byte, worldRead bool, cache string) (*storage.ObjectAttrs, error) {
	if cc.Lock != nil {
		cc.Lock.Lock()
		defer cc.Lock.Unlock()
	}
	if err := cc.check(ctx, nil, &path); err != nil {
		return nil, err
	}
	gen := cc.Uploader[path].Generation + 1
	_, err := cc.UploadClient.Upload(ctx, path, buf, worldRead, cache)
	if err != nil {
		return nil, err
	}
	u := cc.Uploader[path]
	u.Generation = gen
	cc.Uploader[path] = u
	return u.Attrs(path), nil
}
func (cc *ConditionalClient) If(read, write *storage.Conditions) gcs.ConditionalClient {
	return &ConditionalClient{
		UploadClient: cc.UploadClient,
		read:         read,
		write:        write,
		Lock:         cc.Lock,
	}
}
func (cc *ConditionalClient) Open(ctx context.Context, path gcs.Path) (io.ReadCloser, *storage.ReaderObjectAttrs, error) {
	if cc.Lock != nil {
		cc.Lock.RLock()
		defer cc.Lock.RUnlock()
	}
	if err := cc.check(ctx, &path, nil); err != nil {
		return nil, nil, err
	}
	return cc.UploadClient.Open(ctx, path)
}
func (cc *ConditionalClient) Objects(ctx context.Context, path gcs.Path, _, offset string) gcs.Iterator {
	if cc.Lock != nil {
		cc.Lock.RLock()
		defer cc.Lock.RUnlock()
	}
	return cc.UploadClient.Objects(ctx, path, "", offset)
}
func (cc *ConditionalClient) Stat(ctx context.Context, path gcs.Path) (*storage.ObjectAttrs, error) {
	if cc.Lock != nil {
		cc.Lock.RLock()
		defer cc.Lock.RUnlock()
	}
	if err := cc.check(ctx, &path, nil); err != nil {
		return nil, err
	}
	return cc.UploadClient.Stat(ctx, path)
}
type UploadClient struct {
	Client
	Uploader
	Stater
}
func (fuc UploadClient) If(read, write *storage.Conditions) gcs.ConditionalClient {
	return fuc
}
type Stat struct {
	Err   error
	Attrs storage.ObjectAttrs
}
type Stater map[gcs.Path]Stat
func (fs Stater) Stat(ctx context.Context, path gcs.Path) (*storage.ObjectAttrs, error) {
	if err := ctx.Err(); err != nil {
		return nil, fmt.Errorf("injected interrupt: %w", err)
	}
	ret, ok := fs[path]
	if !ok {
		return nil, storage.ErrObjectNotExist
	}
	if ret.Err != nil {
		return nil, fmt.Errorf("injected upload error: %w", ret.Err)
	}
	return &ret.Attrs, nil
}
type Uploader map[gcs.Path]Upload