Exemplo n.º 1
0
func TestPublishDevicesRestartsServer(t *testing.T) {
	starter := &MockServerStarter{}
	dialer := &MockServer{
		Status: wire.StatusSuccess,
		Errs: []error{
			nil, nil, nil, // Successful dial.
			util.Errorf(util.ConnectionResetError, "failed first read"),
			util.Errorf(util.ServerNotAvailable, "failed redial"),
		},
	}
	watcher := deviceWatcherImpl{
		config:      ClientConfig{dialer},
		eventChan:   make(chan DeviceStateChangedEvent),
		startServer: starter.StartServer,
	}

	publishDevices(&watcher)

	assert.Empty(t, dialer.Errs)
	assert.Equal(t, []string{"host:track-devices"}, dialer.Requests)
	assert.Equal(t, []string{"Dial", "SendMessage", "ReadStatus", "ReadMessage", "Dial"}, dialer.Trace)
	err := watcher.err.Load().(*util.Err)
	assert.Equal(t, util.ServerNotAvailable, err.Code)
	assert.Equal(t, 1, starter.startCount)
}
Exemplo n.º 2
0
func (c *CachingDeviceClient) Stat(name string, log *LogEntry) (*goadb.DirEntry, error) {
	dir := path.Dir(name)
	base := path.Base(name)

	if dir == base {
		// Don't ask the cache for the root stat, we never cache the root.
		return c.DeviceClient.Stat(name, log)
	}

	if entries, found := c.Cache.Get(dir); found {
		log.CacheUsed(true)

		if entry, found := entries.ByName[base]; found {
			return entry, nil
		}

		// Cached directory list doesn't have name, so as far as we're concerned the
		// file doesn't exist.
		return nil, util.Errorf(util.FileNoExistError,
			"name '%s' does not exist in cached directory listing", base)
	}
	log.CacheUsed(false)

	// The directory doesn't exist in the cache, so perform a one-off lookup on the device.
	return c.DeviceClient.Stat(name, log)
}
Exemplo n.º 3
0
func TestFileBufferSync(t *testing.T) {
	dev := &delegateDeviceClient{
		stat: statFiles(&goadb.DirEntry{
			Name: "/file",
			Mode: 0664,
		}),
		openRead: openReadString("hello"),
	}
	file := newTestFileBuffer(t, O_RDONLY, FileBufferOptions{
		Path:   "/file",
		Client: dev,
	})
	assert.Equal(t, "hello", file.Contents())

	// Success.
	dev.openRead = openReadString("world")
	err := file.Sync(&LogEntry{})
	assert.NoError(t, err)
	assert.Equal(t, "world", file.Contents())

	// Failure.
	dev.openRead = openReadError(util.Errorf(util.NetworkError, "fail"))
	err = file.Sync(&LogEntry{})
	assert.Equal(t, `NetworkError: error opening file stream on device
caused by NetworkError: fail`, util.ErrorWithCauseChain(err))
	assert.Equal(t, "world", file.Contents())
}
Exemplo n.º 4
0
func readStat(s wire.SyncScanner) (entry *DirEntry, err error) {
	mode, err := s.ReadFileMode()
	if err != nil {
		err = util.WrapErrf(err, "error reading file mode: %v", err)
		return
	}
	size, err := s.ReadInt32()
	if err != nil {
		err = util.WrapErrf(err, "error reading file size: %v", err)
		return
	}
	mtime, err := s.ReadTime()
	if err != nil {
		err = util.WrapErrf(err, "error reading file time: %v", err)
		return
	}

	// adb doesn't indicate when a file doesn't exist, but will return all zeros.
	// Theoretically this could be an actual file, but that's very unlikely.
	if mode == os.FileMode(0) && size == 0 && mtime == zeroTime {
		return nil, util.Errorf(util.FileNoExistError, "file doesn't exist")
	}

	entry = &DirEntry{
		Mode:       mode,
		Size:       size,
		ModifiedAt: mtime,
	}
	return
}
Exemplo n.º 5
0
func parseDeviceShort(line string) (*DeviceInfo, error) {
	fields := strings.Fields(line)
	if len(fields) != 2 {
		return nil, util.Errorf(util.ParseError,
			"malformed device line, expected 2 fields but found %d", len(fields))
	}

	return newDevice(fields[0], map[string]string{})
}
Exemplo n.º 6
0
func statFiles(entries ...*goadb.DirEntry) func(string) (*goadb.DirEntry, error) {
	return func(path string) (*goadb.DirEntry, error) {
		for _, entry := range entries {
			if entry.Name == path {
				return entry, nil
			}
		}
		return nil, util.Errorf(util.FileNoExistError, "%s", path)
	}
}
Exemplo n.º 7
0
func parseDeviceLong(line string) (*DeviceInfo, error) {
	fields := strings.Fields(line)
	if len(fields) < 5 {
		return nil, util.Errorf(util.ParseError,
			"malformed device line, expected at least 5 fields but found %d", len(fields))
	}

	attrs := parseDeviceAttributes(fields[2:])
	return newDevice(fields[0], attrs)
}
Exemplo n.º 8
0
func parseDeviceStates(msg string) (states map[string]DeviceState, err error) {
	states = make(map[string]DeviceState)

	for lineNum, line := range strings.Split(msg, "\n") {
		if len(line) == 0 {
			continue
		}

		fields := strings.Split(line, "\t")
		if len(fields) != 2 {
			err = util.Errorf(util.ParseError, "invalid device state line %d: %s", lineNum, line)
			return
		}

		serial, stateString := fields[0], fields[1]
		state, ok := deviceStateStrings[stateString]
		if !ok {
			err = util.Errorf(util.ParseError, "invalid device state: %s", state)
		}
		states[serial] = state
	}

	return
}
Exemplo n.º 9
0
func stat(conn *wire.SyncConn, path string) (*DirEntry, error) {
	if err := conn.SendOctetString("STAT"); err != nil {
		return nil, err
	}
	if err := conn.SendString(path); err != nil {
		return nil, err
	}

	id, err := conn.ReadOctetString()
	if err != nil {
		return nil, err
	}
	if id != "STAT" {
		return nil, util.Errorf(util.AssertionError, "expected stat ID 'STAT', but got '%s'", id)
	}

	return readStat(conn)
}
Exemplo n.º 10
0
func TestAdbFile_Fsync(t *testing.T) {
	fileBuf := testSingleRegularFileBuffer(t, "hello")
	file := getAdbFile(NewAdbFile(AdbFileOpenOptions{
		FileBuffer: fileBuf,
	}))
	assert.Equal(t, "hello", fileBuf.Contents())

	// Success.
	fileBuf.Client.(*delegateDeviceClient).openRead = openReadString("world")
	status := file.Fsync(0)
	assertStatusOk(t, status)
	assert.Equal(t, "world", fileBuf.Contents())

	// Failure.
	fileBuf.Client.(*delegateDeviceClient).openRead = openReadError(util.Errorf(util.NetworkError, ""))
	status = file.Fsync(0)
	assert.Equal(t, fuse.EIO, status)
	assert.Equal(t, "world", fileBuf.Contents())
}
Exemplo n.º 11
0
// prepareCommandLine validates the command and argument strings, quotes
// arguments if required, and joins them into a valid adb command string.
func prepareCommandLine(cmd string, args ...string) (string, error) {
	if isBlank(cmd) {
		return "", util.AssertionErrorf("command cannot be empty")
	}

	for i, arg := range args {
		if strings.ContainsRune(arg, '"') {
			return "", util.Errorf(util.ParseError, "arg at index %d contains an invalid double quote: %s", i, arg)
		}
		if containsWhitespace(arg) {
			args[i] = fmt.Sprintf("\"%s\"", arg)
		}
	}

	// Prepend the command to the args array.
	if len(args) > 0 {
		cmd = fmt.Sprintf("%s %s", cmd, strings.Join(args, " "))
	}

	return cmd, nil
}
Exemplo n.º 12
0
func TestCachingDeviceClientStat_Miss(t *testing.T) {
	client := &CachingDeviceClient{
		DeviceClient: &delegateDeviceClient{
			stat: func(path string) (*goadb.DirEntry, error) {
				if path == "/foo/bar" {
					return &goadb.DirEntry{Name: "baz"}, nil
				}
				return nil, util.Errorf(util.FileNoExistError, "")
			},
		},
		Cache: &delegateDirEntryCache{
			DoGet: func(path string) (entries *CachedDirEntries, found bool) {
				return nil, false
			},
		},
	}

	entry, err := client.Stat("/foo/bar", &LogEntry{})
	assert.NoError(t, err)
	assert.Equal(t, "baz", entry.Name)
}
Exemplo n.º 13
0
func (c *DeviceClient) GetDeviceInfo() (*DeviceInfo, error) {
	// Adb doesn't actually provide a way to get this for an individual device,
	// so we have to just list devices and find ourselves.

	serial, err := c.GetSerial()
	if err != nil {
		return nil, wrapClientError(err, c, "GetDeviceInfo(GetSerial)")
	}

	devices, err := c.deviceListFunc()
	if err != nil {
		return nil, wrapClientError(err, c, "GetDeviceInfo(ListDevices)")
	}

	for _, deviceInfo := range devices {
		if deviceInfo.Serial == serial {
			return deviceInfo, nil
		}
	}

	err = util.Errorf(util.DeviceNotFound, "device list doesn't contain serial %s", serial)
	return nil, wrapClientError(err, c, "GetDeviceInfo")
}