diff --git a/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD new file mode 100644 index 000000000..2848d77d0 --- /dev/null +++ b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD @@ -0,0 +1,35 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +load("@rules_java//java:java_library.bzl", "java_library") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//src/devtools/mobileharness/fe/v6:visibility"], +) + +java_library( + name = "config_converter", + srcs = ["ConfigConverter.java"], + deps = [ + "//src/devtools/mobileharness/api/deviceconfig/proto:basic_java_proto", + "//src/devtools/mobileharness/api/deviceconfig/proto:lab_java_proto", + "//src/devtools/mobileharness/api/model/proto:device_java_proto", + "//src/devtools/mobileharness/fe/v6/service/proto/common:common_resources_java_proto", + "//src/devtools/mobileharness/fe/v6/service/proto/config:config_resources_java_proto", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + ], +) diff --git a/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigConverter.java b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigConverter.java new file mode 100644 index 000000000..95c45fe46 --- /dev/null +++ b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigConverter.java @@ -0,0 +1,337 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.devtools.mobileharness.fe.v6.service.config.util; + +import static com.google.common.collect.ImmutableList.toImmutableList; + +import com.google.common.collect.ImmutableList; +import com.google.devtools.mobileharness.api.deviceconfig.proto.Basic.BasicDeviceConfig; +import com.google.devtools.mobileharness.api.deviceconfig.proto.Lab.DetectorSpecs; +import com.google.devtools.mobileharness.api.deviceconfig.proto.Lab.DetectorSpecs.ManekiDetectorSpecs; +import com.google.devtools.mobileharness.api.deviceconfig.proto.Lab.LabConfig; +import com.google.devtools.mobileharness.api.model.proto.Device.DeviceCompositeDimension; +import com.google.devtools.mobileharness.api.model.proto.Device.DeviceDimension; +import com.google.devtools.mobileharness.fe.v6.service.proto.common.PermissionInfo; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.DeviceConfig; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.DeviceConfigMode; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.DeviceDiscoverySettings; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.HostConfig; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.HostPermissions; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.HostProperty; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.ManekiSpec; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.StabilitySettings; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.WifiConfig; +import com.google.protobuf.Int32Value; +import java.util.List; + +/** Utility for converting between internal and FE configuration protos. */ +public final class ConfigConverter { + + private ConfigConverter() {} + + /** Converts internal {@link BasicDeviceConfig} to FE {@link DeviceConfig}. */ + public static DeviceConfig toFeDeviceConfig(BasicDeviceConfig basicConfig) { + DeviceConfig.Builder builder = DeviceConfig.newBuilder(); + + // Permissions + builder.setPermissions( + PermissionInfo.newBuilder() + .addAllOwners(basicConfig.getOwnerList()) + .addAllExecutors(basicConfig.getExecutorList()) + .build()); + + // Wifi + if (basicConfig.hasDefaultWifi()) { + com.google.devtools.mobileharness.api.deviceconfig.proto.Basic.WifiConfig internalWifi = + basicConfig.getDefaultWifi(); + builder.setWifi( + WifiConfig.newBuilder() + .setSsid(internalWifi.getSsid()) + .setPsk(internalWifi.getPsk()) + .setScanSsid(internalWifi.getScanSsid()) + .setType(internalWifi.getSsid().isEmpty() ? "none" : "custom") + .build()); + } + + // Dimensions + if (basicConfig.hasCompositeDimension()) { + builder.setDimensions( + DeviceConfig.Dimensions.newBuilder() + .addAllSupported( + basicConfig.getCompositeDimension().getSupportedDimensionList().stream() + .map( + d -> + com.google.devtools.mobileharness.fe.v6.service.proto.common + .DeviceDimension.newBuilder() + .setName(d.getName()) + .setValue(d.getValue()) + .build()) + .collect(toImmutableList())) + .addAllRequired( + basicConfig.getCompositeDimension().getRequiredDimensionList().stream() + .map( + d -> + com.google.devtools.mobileharness.fe.v6.service.proto.common + .DeviceDimension.newBuilder() + .setName(d.getName()) + .setValue(d.getValue()) + .build()) + .collect(toImmutableList())) + .build()); + } + + // Stability Settings + StabilitySettings.Builder settingsBuilder = StabilitySettings.newBuilder(); + if (basicConfig.hasMaxConsecutiveTest()) { + settingsBuilder.setMaxConsecutiveTest(basicConfig.getMaxConsecutiveTest().getValue()); + } + if (basicConfig.hasMaxConsecutiveFail()) { + settingsBuilder.setMaxConsecutiveFail(basicConfig.getMaxConsecutiveFail().getValue()); + } + return builder.setSettings(settingsBuilder.build()).build(); + } + + /** Converts FE {@link DeviceConfig} to internal {@link BasicDeviceConfig}. */ + public static BasicDeviceConfig toBasicDeviceConfig(DeviceConfig feConfig) { + BasicDeviceConfig.Builder builder = BasicDeviceConfig.newBuilder(); + + // Permissions + if (feConfig.hasPermissions()) { + builder + .addAllOwner(feConfig.getPermissions().getOwnersList()) + .addAllExecutor(feConfig.getPermissions().getExecutorsList()); + } + + // Wifi + if (feConfig.hasWifi()) { + builder.setDefaultWifi( + com.google.devtools.mobileharness.api.deviceconfig.proto.Basic.WifiConfig.newBuilder() + .setSsid(feConfig.getWifi().getSsid()) + .setPsk(feConfig.getWifi().getPsk()) + .setScanSsid(feConfig.getWifi().getScanSsid()) + .build()); + } + + // Dimensions + if (feConfig.hasDimensions()) { + DeviceCompositeDimension dimension = + DeviceCompositeDimension.newBuilder() + .addAllSupportedDimension( + feConfig.getDimensions().getSupportedList().stream() + .map( + d -> + DeviceDimension.newBuilder() + .setName(d.getName()) + .setValue(d.getValue()) + .build()) + .collect(toImmutableList())) + .addAllRequiredDimension( + feConfig.getDimensions().getRequiredList().stream() + .map( + d -> + DeviceDimension.newBuilder() + .setName(d.getName()) + .setValue(d.getValue()) + .build()) + .collect(toImmutableList())) + .build(); + builder.setCompositeDimension(dimension); + } + + // Stability Settings + if (feConfig.hasSettings()) { + builder + .setMaxConsecutiveTest(Int32Value.of(feConfig.getSettings().getMaxConsecutiveTest())) + .setMaxConsecutiveFail(Int32Value.of(feConfig.getSettings().getMaxConsecutiveFail())); + } + + return builder.build(); + } + + /** Converts internal {@link LabConfig} to FE {@link HostConfig}. */ + public static HostConfig toFeHostConfig(LabConfig labConfig) { + HostConfig.Builder builder = HostConfig.newBuilder(); + + // Permissions + builder.setPermissions( + HostPermissions.newBuilder() + .addAllHostAdmins(labConfig.getDefaultDeviceConfig().getOwnerList()) + .build()); + + // Device Config Mode + DeviceConfigMode mode = + labConfig.getHostProperties().getHostPropertyList().stream() + .anyMatch( + p -> p.getKey().equals("device_config_mode") && p.getValue().equals("host")) + ? DeviceConfigMode.SHARED + : DeviceConfigMode.PER_DEVICE; + builder.setDeviceConfigMode(mode); + + // Device Config + if (labConfig.hasDefaultDeviceConfig()) { + builder.setDeviceConfig(toFeDeviceConfig(labConfig.getDefaultDeviceConfig())); + } + + // Host Properties + builder.addAllHostProperties( + labConfig.getHostProperties().getHostPropertyList().stream() + .filter(p -> !p.getKey().equals("device_config_mode")) + .map(p -> HostProperty.newBuilder().setKey(p.getKey()).setValue(p.getValue()).build()) + .collect(toImmutableList())); + + // Device Discovery + DeviceDiscoverySettings.Builder discoveryBuilder = + DeviceDiscoverySettings.newBuilder() + .addAllMonitoredDeviceUuids(labConfig.getMonitoredDeviceUuidList()) + .addAllTestbedUuids(labConfig.getTestbedUuidList()) + .addAllMiscDeviceUuids(labConfig.getMiscDeviceUuidList()) + .addAllOverTcpIps(labConfig.getOverTcpIpList()) + .addAllOverSshDevices( + labConfig.getOverSshList().stream() + .map( + d -> + DeviceDiscoverySettings.OverSshDevice.newBuilder() + .setIpAddress(d.getIpAddress()) + .setUsername(d.getUsername()) + .setPassword(d.getPassword()) + .setSshDeviceType(d.getSshDeviceType()) + .build()) + .collect(toImmutableList())); + if (labConfig.hasDetectorSpecs()) { + discoveryBuilder.addAllManekiSpecs(toFeManekiSpecs(labConfig.getDetectorSpecs())); + } + return builder.setDeviceDiscovery(discoveryBuilder.build()).build(); + } + + private static ImmutableList toFeManekiSpecs(DetectorSpecs detectorSpecs) { + ImmutableList.Builder feSpecs = ImmutableList.builder(); + if (detectorSpecs.hasManekiDetectorSpecs()) { + ManekiDetectorSpecs maneki = detectorSpecs.getManekiDetectorSpecs(); + maneki + .getManekiAndroidDeviceDiscoverySpecList() + .forEach( + s -> + feSpecs.add( + ManekiSpec.newBuilder() + .setType("android") + .setMacAddress(s.getMacAddress()) + .build())); + maneki + .getManekiRokuDeviceDiscoverySpecList() + .forEach( + s -> + feSpecs.add( + ManekiSpec.newBuilder() + .setType("roku") + .setMacAddress(s.getMacAddress()) + .build())); + maneki + .getManekiRdkDeviceDiscoverySpecList() + .forEach( + s -> + feSpecs.add( + ManekiSpec.newBuilder() + .setType("rdk") + .setMacAddress(s.getMacAddress()) + .build())); + maneki + .getManekiRaspberryPiDeviceDiscoverySpecList() + .forEach( + s -> + feSpecs.add( + ManekiSpec.newBuilder() + .setType("raspberry_pi") + .setMacAddress(s.getMacAddress()) + .build())); + maneki + .getManekiPs4DeviceDiscoverySpecList() + .forEach( + s -> + feSpecs.add( + ManekiSpec.newBuilder() + .setType("ps4") + .setMacAddress(s.getWinMacAddress()) + .build())); + maneki + .getManekiPs5DeviceDiscoverySpecList() + .forEach( + s -> + feSpecs.add( + ManekiSpec.newBuilder() + .setType("ps5") + .setMacAddress(s.getWinMacAddress()) + .build())); + maneki + .getManekiGenericDeviceDiscoverySpecList() + .forEach( + s -> + feSpecs.add( + ManekiSpec.newBuilder() + .setType("generic") + .setMacAddress(s.getMacAddress()) + .build())); + } + return feSpecs.build(); + } + + public static DetectorSpecs toInternalDetectorSpecs(List feSpecs) { + ManekiDetectorSpecs.Builder manekiBuilder = ManekiDetectorSpecs.newBuilder(); + for (ManekiSpec spec : feSpecs) { + switch (spec.getType()) { + case "android" -> + manekiBuilder.addManekiAndroidDeviceDiscoverySpec( + DetectorSpecs.ManekiDetectorSpecs.ManekiAndroidDeviceDiscoverySpec.newBuilder() + .setMacAddress(spec.getMacAddress()) + .build()); + case "roku" -> + manekiBuilder.addManekiRokuDeviceDiscoverySpec( + DetectorSpecs.ManekiDetectorSpecs.ManekiRokuDeviceDiscoverySpec.newBuilder() + .setMacAddress(spec.getMacAddress()) + .build()); + case "rdk" -> + manekiBuilder.addManekiRdkDeviceDiscoverySpec( + DetectorSpecs.ManekiDetectorSpecs.ManekiRdkDeviceDiscoverySpec.newBuilder() + .setMacAddress(spec.getMacAddress()) + .build()); + case "raspberry_pi" -> + manekiBuilder.addManekiRaspberryPiDeviceDiscoverySpec( + DetectorSpecs.ManekiDetectorSpecs.ManekiRaspberryPiDeviceDiscoverySpec.newBuilder() + .setMacAddress(spec.getMacAddress()) + .build()); + case "ps4" -> + manekiBuilder.addManekiPs4DeviceDiscoverySpec( + DetectorSpecs.ManekiDetectorSpecs.ManekiPs4DeviceDiscoverySpec.newBuilder() + .setWinMacAddress(spec.getMacAddress()) + .build()); + case "ps5" -> + manekiBuilder.addManekiPs5DeviceDiscoverySpec( + DetectorSpecs.ManekiDetectorSpecs.ManekiPs5DeviceDiscoverySpec.newBuilder() + .setWinMacAddress(spec.getMacAddress()) + .build()); + case "generic" -> + manekiBuilder.addManekiGenericDeviceDiscoverySpec( + DetectorSpecs.ManekiDetectorSpecs.ManekiGenericDeviceDiscoverySpec.newBuilder() + .setMacAddress(spec.getMacAddress()) + .build()); + default -> { + // Ignore unknown types + } + } + } + return DetectorSpecs.newBuilder().setManekiDetectorSpecs(manekiBuilder.build()).build(); + } +} diff --git a/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD b/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD new file mode 100644 index 000000000..99465728d --- /dev/null +++ b/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD @@ -0,0 +1,48 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +load("@rules_java//java:java_library.bzl", "java_library") +load("//src/javatests/com/google/devtools/mobileharness/builddefs:junit_test_suites.bzl", "junit_test_suites") + +package( + default_applicable_licenses = ["//:license"], +) + +java_library( + name = "util_tests", + testonly = 1, + srcs = [ + "ConfigConverterTest.java", + ], + deps = [ + "//src/devtools/mobileharness/api/deviceconfig/proto:basic_java_proto", + "//src/devtools/mobileharness/api/deviceconfig/proto:lab_java_proto", + "//src/devtools/mobileharness/api/model/proto:device_java_proto", + "//src/devtools/mobileharness/api/model/proto:lab_java_proto", + "//src/devtools/mobileharness/fe/v6/service/proto/common:common_resources_java_proto", + "//src/devtools/mobileharness/fe/v6/service/proto/config:config_resources_java_proto", + "//src/java/com/google/devtools/mobileharness/fe/v6/service/config/util:config_converter", + "//src/javatests/com/google/devtools/mobileharness/builddefs:truth", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:junit_junit", + ], +) + +junit_test_suites( + name = "gen_tests", + sizes = ["small"], + deps = [":util_tests"], +) diff --git a/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigConverterTest.java b/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigConverterTest.java new file mode 100644 index 000000000..31a19e35f --- /dev/null +++ b/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigConverterTest.java @@ -0,0 +1,356 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.devtools.mobileharness.fe.v6.service.config.util; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import com.google.devtools.mobileharness.api.deviceconfig.proto.Basic.BasicDeviceConfig; +import com.google.devtools.mobileharness.api.deviceconfig.proto.Lab.DetectorSpecs; +import com.google.devtools.mobileharness.api.deviceconfig.proto.Lab.DetectorSpecs.ManekiDetectorSpecs; +import com.google.devtools.mobileharness.api.deviceconfig.proto.Lab.LabConfig; +import com.google.devtools.mobileharness.api.deviceconfig.proto.Lab.OverSshDevice; +import com.google.devtools.mobileharness.api.model.proto.Device.DeviceCompositeDimension; +import com.google.devtools.mobileharness.api.model.proto.Device.DeviceDimension; +import com.google.devtools.mobileharness.api.model.proto.Lab.HostProperties; +import com.google.devtools.mobileharness.api.model.proto.Lab.HostProperty; +import com.google.devtools.mobileharness.fe.v6.service.proto.common.PermissionInfo; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.DeviceConfig; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.DeviceConfigMode; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.HostConfig; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.ManekiSpec; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.StabilitySettings; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.WifiConfig; +import com.google.protobuf.Int32Value; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class ConfigConverterTest { + + @Test + public void toFeDeviceConfig_fullMappings() { + BasicDeviceConfig basicConfig = + BasicDeviceConfig.newBuilder() + .addOwner("owner1") + .addExecutor("exec1") + .setDefaultWifi( + com.google.devtools.mobileharness.api.deviceconfig.proto.Basic.WifiConfig + .newBuilder() + .setSsid("my-ssid") + .setPsk("my-psk") + .setScanSsid(true) + .build()) + .setCompositeDimension( + DeviceCompositeDimension.newBuilder() + .addSupportedDimension( + DeviceDimension.newBuilder().setName("n1").setValue("v1").build()) + .addRequiredDimension( + DeviceDimension.newBuilder().setName("n2").setValue("v2").build()) + .build()) + .setMaxConsecutiveTest(Int32Value.of(10)) + .setMaxConsecutiveFail(Int32Value.of(5)) + .build(); + + DeviceConfig feConfig = ConfigConverter.toFeDeviceConfig(basicConfig); + + assertThat(feConfig.getPermissions().getOwnersList()).containsExactly("owner1"); + assertThat(feConfig.getPermissions().getExecutorsList()).containsExactly("exec1"); + assertThat(feConfig.getWifi().getSsid()).isEqualTo("my-ssid"); + assertThat(feConfig.getWifi().getPsk()).isEqualTo("my-psk"); + assertThat(feConfig.getWifi().getScanSsid()).isTrue(); + assertThat(feConfig.getWifi().getType()).isEqualTo("custom"); + assertThat(feConfig.getDimensions().getSupportedList().get(0).getName()).isEqualTo("n1"); + assertThat(feConfig.getDimensions().getRequiredList().get(0).getName()).isEqualTo("n2"); + assertThat(feConfig.getSettings().getMaxConsecutiveTest()).isEqualTo(10); + assertThat(feConfig.getSettings().getMaxConsecutiveFail()).isEqualTo(5); + } + + @Test + public void toFeDeviceConfig_emptyWifi_noneType() { + BasicDeviceConfig basicConfig = + BasicDeviceConfig.newBuilder() + .setDefaultWifi( + com.google.devtools.mobileharness.api.deviceconfig.proto.Basic.WifiConfig + .newBuilder() + .setSsid("") + .build()) + .build(); + + DeviceConfig feConfig = ConfigConverter.toFeDeviceConfig(basicConfig); + + assertThat(feConfig.getWifi().getType()).isEqualTo("none"); + } + + @Test + public void toBasicDeviceConfig_fullMappings() { + DeviceConfig feConfig = + DeviceConfig.newBuilder() + .setPermissions(PermissionInfo.newBuilder().addOwners("o1").addExecutors("e1").build()) + .setWifi(WifiConfig.newBuilder().setSsid("s1").setPsk("p1").setScanSsid(false).build()) + .setDimensions( + DeviceConfig.Dimensions.newBuilder() + .addSupported( + com.google.devtools.mobileharness.fe.v6.service.proto.common.DeviceDimension + .newBuilder() + .setName("sn") + .setValue("sv") + .build()) + .addRequired( + com.google.devtools.mobileharness.fe.v6.service.proto.common.DeviceDimension + .newBuilder() + .setName("rn") + .setValue("rv") + .build()) + .build()) + .setSettings( + StabilitySettings.newBuilder() + .setMaxConsecutiveTest(20) + .setMaxConsecutiveFail(3) + .build()) + .build(); + + BasicDeviceConfig basicConfig = ConfigConverter.toBasicDeviceConfig(feConfig); + + assertThat(basicConfig.getOwnerList()).containsExactly("o1"); + assertThat(basicConfig.getExecutorList()).containsExactly("e1"); + assertThat(basicConfig.getDefaultWifi().getSsid()).isEqualTo("s1"); + assertThat(basicConfig.getCompositeDimension().getSupportedDimensionList().get(0).getName()) + .isEqualTo("sn"); + assertThat(basicConfig.getCompositeDimension().getRequiredDimensionList().get(0).getName()) + .isEqualTo("rn"); + assertThat(basicConfig.getMaxConsecutiveTest().getValue()).isEqualTo(20); + assertThat(basicConfig.getMaxConsecutiveFail().getValue()).isEqualTo(3); + } + + @Test + public void toFeHostConfig_fullMappings() { + LabConfig labConfig = + LabConfig.newBuilder() + .setDefaultDeviceConfig(BasicDeviceConfig.newBuilder().addOwner("admin").build()) + .setHostProperties( + HostProperties.newBuilder() + .addHostProperty(HostProperty.newBuilder().setKey("k1").setValue("v1").build()) + .build()) + .addMonitoredDeviceUuid("u1") + .addOverTcpIp("1.1.1.1") + .addOverSsh( + OverSshDevice.newBuilder() + .setIpAddress("2.2.2.2") + .setUsername("user") + .setPassword("pass") + .setSshDeviceType("android") + .build()) + .setDetectorSpecs( + DetectorSpecs.newBuilder() + .setManekiDetectorSpecs( + ManekiDetectorSpecs.newBuilder() + .addManekiAndroidDeviceDiscoverySpec( + ManekiDetectorSpecs.ManekiAndroidDeviceDiscoverySpec.newBuilder() + .setMacAddress("mac1") + .build()) + .build()) + .build()) + .build(); + + HostConfig feConfig = ConfigConverter.toFeHostConfig(labConfig); + + assertThat(feConfig.getPermissions().getHostAdminsList()).containsExactly("admin"); + assertThat(feConfig.getHostPropertiesList().get(0).getKey()).isEqualTo("k1"); + assertThat(feConfig.getDeviceDiscovery().getMonitoredDeviceUuidsList()).containsExactly("u1"); + assertThat(feConfig.getDeviceDiscovery().getOverTcpIpsList()).containsExactly("1.1.1.1"); + assertThat(feConfig.getDeviceDiscovery().getOverSshDevicesList().get(0).getIpAddress()) + .isEqualTo("2.2.2.2"); + assertThat(feConfig.getDeviceDiscovery().getManekiSpecsList().get(0).getType()) + .isEqualTo("android"); + } + + @Test + public void toFeManekiSpecs_allTypes() { + DetectorSpecs specs = + DetectorSpecs.newBuilder() + .setManekiDetectorSpecs( + ManekiDetectorSpecs.newBuilder() + .addManekiAndroidDeviceDiscoverySpec( + ManekiDetectorSpecs.ManekiAndroidDeviceDiscoverySpec.newBuilder() + .setMacAddress("m1") + .build()) + .addManekiRokuDeviceDiscoverySpec( + ManekiDetectorSpecs.ManekiRokuDeviceDiscoverySpec.newBuilder() + .setMacAddress("m2") + .build()) + .addManekiRdkDeviceDiscoverySpec( + ManekiDetectorSpecs.ManekiRdkDeviceDiscoverySpec.newBuilder() + .setMacAddress("m3") + .build()) + .addManekiRaspberryPiDeviceDiscoverySpec( + ManekiDetectorSpecs.ManekiRaspberryPiDeviceDiscoverySpec.newBuilder() + .setMacAddress("m4") + .build()) + .addManekiPs4DeviceDiscoverySpec( + ManekiDetectorSpecs.ManekiPs4DeviceDiscoverySpec.newBuilder() + .setWinMacAddress("m5") + .build()) + .addManekiPs5DeviceDiscoverySpec( + ManekiDetectorSpecs.ManekiPs5DeviceDiscoverySpec.newBuilder() + .setWinMacAddress("m6") + .build()) + .addManekiGenericDeviceDiscoverySpec( + ManekiDetectorSpecs.ManekiGenericDeviceDiscoverySpec.newBuilder() + .setMacAddress("m7") + .build()) + .build()) + .build(); + + HostConfig feConfig = + ConfigConverter.toFeHostConfig(LabConfig.newBuilder().setDetectorSpecs(specs).build()); + List manekiSpecs = feConfig.getDeviceDiscovery().getManekiSpecsList(); + + assertThat(manekiSpecs).hasSize(7); + assertThat(manekiSpecs.get(0).getType()).isEqualTo("android"); + assertThat(manekiSpecs.get(1).getType()).isEqualTo("roku"); + assertThat(manekiSpecs.get(2).getType()).isEqualTo("rdk"); + assertThat(manekiSpecs.get(3).getType()).isEqualTo("raspberry_pi"); + assertThat(manekiSpecs.get(4).getType()).isEqualTo("ps4"); + assertThat(manekiSpecs.get(5).getType()).isEqualTo("ps5"); + assertThat(manekiSpecs.get(6).getType()).isEqualTo("generic"); + } + + @Test + public void toInternalDetectorSpecs_allTypes() { + ImmutableList feSpecs = + ImmutableList.of( + ManekiSpec.newBuilder().setType("android").setMacAddress("m1").build(), + ManekiSpec.newBuilder().setType("roku").setMacAddress("m2").build(), + ManekiSpec.newBuilder().setType("rdk").setMacAddress("m3").build(), + ManekiSpec.newBuilder().setType("raspberry_pi").setMacAddress("m4").build(), + ManekiSpec.newBuilder().setType("ps4").setMacAddress("m5").build(), + ManekiSpec.newBuilder().setType("ps5").setMacAddress("m6").build(), + ManekiSpec.newBuilder().setType("generic").setMacAddress("m7").build(), + ManekiSpec.newBuilder().setType("unknown").setMacAddress("m8").build()); + + DetectorSpecs specs = ConfigConverter.toInternalDetectorSpecs(feSpecs); + ManekiDetectorSpecs maneki = specs.getManekiDetectorSpecs(); + + assertThat(maneki.getManekiAndroidDeviceDiscoverySpecCount()).isEqualTo(1); + assertThat(maneki.getManekiRokuDeviceDiscoverySpecCount()).isEqualTo(1); + assertThat(maneki.getManekiRdkDeviceDiscoverySpecCount()).isEqualTo(1); + assertThat(maneki.getManekiRaspberryPiDeviceDiscoverySpecCount()).isEqualTo(1); + assertThat(maneki.getManekiPs4DeviceDiscoverySpecCount()).isEqualTo(1); + assertThat(maneki.getManekiPs5DeviceDiscoverySpecCount()).isEqualTo(1); + assertThat(maneki.getManekiGenericDeviceDiscoverySpecCount()).isEqualTo(1); + } + + @Test + public void toFeHostConfig_extractsHostAdminsFromDefaultDeviceConfig() { + LabConfig labConfig = + LabConfig.newBuilder() + .setDefaultDeviceConfig( + BasicDeviceConfig.newBuilder().addOwner("admin1").addOwner("admin2").build()) + .build(); + + HostConfig feConfig = ConfigConverter.toFeHostConfig(labConfig); + + assertThat(feConfig.getPermissions().getHostAdminsList()).containsExactly("admin1", "admin2"); + } + + @Test + public void toFeHostConfig_detectsSharedMode_fromPropertyPresence() { + LabConfig labConfig = + LabConfig.newBuilder() + .setHostProperties( + HostProperties.newBuilder() + .addHostProperty( + HostProperty.newBuilder() + .setKey("device_config_mode") + .setValue("host") + .build()) + .build()) + .build(); + + HostConfig feConfig = ConfigConverter.toFeHostConfig(labConfig); + + assertThat(feConfig.getDeviceConfigMode()).isEqualTo(DeviceConfigMode.SHARED); + } + + @Test + public void toFeHostConfig_detectsPerDeviceMode_fromPropertyAbsence() { + LabConfig labConfig = + LabConfig.newBuilder() + .setHostProperties( + HostProperties.newBuilder() + .addHostProperty( + HostProperty.newBuilder().setKey("other").setValue("val").build()) + .build()) + .build(); + + HostConfig feConfig = ConfigConverter.toFeHostConfig(labConfig); + + assertThat(feConfig.getDeviceConfigMode()).isEqualTo(DeviceConfigMode.PER_DEVICE); + } + + @Test + public void toFeHostConfig_detectsPerDeviceMode_whenValueNotHost() { + LabConfig labConfig = + LabConfig.newBuilder() + .setHostProperties( + HostProperties.newBuilder() + .addHostProperty( + HostProperty.newBuilder() + .setKey("device_config_mode") + .setValue("something_else") + .build()) + .build()) + .build(); + + HostConfig feConfig = ConfigConverter.toFeHostConfig(labConfig); + + assertThat(feConfig.getDeviceConfigMode()).isEqualTo(DeviceConfigMode.PER_DEVICE); + } + + @Test + public void toFeHostConfig_detectsPerDeviceMode_whenKeyNotDeviceConfigMode() { + LabConfig labConfig = + LabConfig.newBuilder() + .setHostProperties( + HostProperties.newBuilder() + .addHostProperty( + HostProperty.newBuilder().setKey("other_key").setValue("host").build()) + .build()) + .build(); + + HostConfig feConfig = ConfigConverter.toFeHostConfig(labConfig); + + assertThat(feConfig.getDeviceConfigMode()).isEqualTo(DeviceConfigMode.PER_DEVICE); + } + + @Test + public void toFeHostConfig_convertsDefaultDeviceConfig() { + LabConfig labConfig = + LabConfig.newBuilder() + .setDefaultDeviceConfig(BasicDeviceConfig.newBuilder().addOwner("owner1").build()) + .build(); + + HostConfig feConfig = ConfigConverter.toFeHostConfig(labConfig); + + assertThat(feConfig.hasDeviceConfig()).isTrue(); + assertThat(feConfig.getDeviceConfig().getPermissions().getOwnersList()) + .containsExactly("owner1"); + } +}