diff --git a/backend/internal/service/device_service.go b/backend/internal/service/device_service.go index 975d428..c6b2975 100644 --- a/backend/internal/service/device_service.go +++ b/backend/internal/service/device_service.go @@ -109,6 +109,11 @@ func (s *DeviceService) SetOnline(deviceID string, online bool) (model.Device, b func (s *DeviceService) ListCandidates(currentDeviceID string) []model.Device { current, _ := s.store.GetDevice(currentDeviceID) + currentNetworkGroupKey := strings.TrimSpace(current.NetworkGroupKey) + if currentNetworkGroupKey == "" { + return nil + } + devices := s.store.ListDevices() s.applyPresence(devices) candidates := make([]model.Device, 0, len(devices)) @@ -117,15 +122,13 @@ func (s *DeviceService) ListCandidates(currentDeviceID string) []model.Device { if device.ID == currentDeviceID || !device.IsOnline { continue } + if strings.TrimSpace(device.NetworkGroupKey) != currentNetworkGroupKey { + continue + } candidates = append(candidates, device) } sort.SliceStable(candidates, func(i, j int) bool { - leftSameNetwork := current.NetworkGroupKey != "" && candidates[i].NetworkGroupKey == current.NetworkGroupKey - rightSameNetwork := current.NetworkGroupKey != "" && candidates[j].NetworkGroupKey == current.NetworkGroupKey - if leftSameNetwork != rightSameNetwork { - return leftSameNetwork - } return candidates[i].LastSeenAt.After(candidates[j].LastSeenAt) }) diff --git a/backend/internal/service/device_service_test.go b/backend/internal/service/device_service_test.go index ef5baf0..c3851b3 100644 --- a/backend/internal/service/device_service_test.go +++ b/backend/internal/service/device_service_test.go @@ -56,3 +56,60 @@ func TestRegisterReusesKnownDeviceOnlyWithValidToken(t *testing.T) { t.Fatal("expected rotated device token to validate") } } + +func TestListCandidatesOnlyReturnsSameNetworkDevices(t *testing.T) { + memStore := store.NewMemoryStore(model.RuntimeConfig{}) + deviceService := NewDeviceService(memStore, nil, nil) + + current, _ := deviceService.Register(RegisterDeviceInput{ + DeviceID: "current", + Name: "Current", + Type: "desktop", + NetworkGroupKey: "192.168.1.10", + }, "ua/1.0", "") + + sameNetwork, _ := deviceService.Register(RegisterDeviceInput{ + DeviceID: "same-network", + Name: "Same Network", + Type: "phone", + NetworkGroupKey: "192.168.1.10", + }, "ua/1.0", "") + + _, _ = deviceService.Register(RegisterDeviceInput{ + DeviceID: "other-network", + Name: "Other Network", + Type: "phone", + NetworkGroupKey: "10.0.0.5", + }, "ua/1.0", "") + + candidates := deviceService.ListCandidates(current.ID) + if len(candidates) != 1 { + t.Fatalf("expected 1 same-network candidate, got %d", len(candidates)) + } + if candidates[0].ID != sameNetwork.ID { + t.Fatalf("expected candidate %q, got %q", sameNetwork.ID, candidates[0].ID) + } +} + +func TestListCandidatesReturnsEmptyWithoutNetworkGroupKey(t *testing.T) { + memStore := store.NewMemoryStore(model.RuntimeConfig{}) + deviceService := NewDeviceService(memStore, nil, nil) + + current, _ := deviceService.Register(RegisterDeviceInput{ + DeviceID: "current", + Name: "Current", + Type: "desktop", + }, "ua/1.0", "") + + _, _ = deviceService.Register(RegisterDeviceInput{ + DeviceID: "same-network", + Name: "Same Network", + Type: "phone", + NetworkGroupKey: "192.168.1.10", + }, "ua/1.0", "") + + candidates := deviceService.ListCandidates(current.ID) + if len(candidates) != 0 { + t.Fatalf("expected no candidates without a local network group key, got %d", len(candidates)) + } +}