@Override
    public Object getServiceDetail(String namespaceId, String groupName, String serviceName) throws NacosException {
        Service service = Service.newService(namespaceId, groupName, serviceName);
        if (!ServiceManager.getInstance().containSingleton(service)) {
            throw new NacosException(NacosException.NOT_FOUND,
                    String.format("service %s@@%s is not found!", groupName, serviceName));
        }
        
        Optional<ServiceMetadata> metadata = metadataManager.getServiceMetadata(service);
        ServiceMetadata detailedService = metadata.orElseGet(ServiceMetadata::new);
        
        ObjectNode serviceObject = JacksonUtils.createEmptyJsonNode();
        serviceObject.put(FieldsConstants.NAME, serviceName);
        serviceObject.put(FieldsConstants.GROUP_NAME, groupName);
        serviceObject.put(FieldsConstants.PROTECT_THRESHOLD, detailedService.getProtectThreshold());
        serviceObject.replace(FieldsConstants.SELECTOR, JacksonUtils.transferToJsonNode(detailedService.getSelector()));
        serviceObject.replace(FieldsConstants.METADATA,
                JacksonUtils.transferToJsonNode(detailedService.getExtendData()));
        
        ObjectNode detailView = JacksonUtils.createEmptyJsonNode();
        detailView.replace(FieldsConstants.SERVICE, serviceObject);
        
        List<com.alibaba.nacos.api.naming.pojo.Cluster> clusters = new ArrayList<>();
        
        for (String each : serviceStorage.getClusters(service)) {
            ClusterMetadata clusterMetadata =
                    detailedService.getClusters().containsKey(each) ? detailedService.getClusters().get(each)
                            : new ClusterMetadata();
            com.alibaba.nacos.api.naming.pojo.Cluster clusterView = new Cluster();
            clusterView.setName(each);
            clusterView.setHealthChecker(clusterMetadata.getHealthChecker());
            clusterView.setMetadata(clusterMetadata.getExtendData());
            clusterView.setUseIPPort4Check(clusterMetadata.isUseInstancePortForCheck());
            clusterView.setDefaultPort(DEFAULT_PORT);
            clusterView.setDefaultCheckPort(clusterMetadata.getHealthyCheckPort());
            clusterView.setServiceName(service.getGroupedServiceName());
            clusters.add(clusterView);
        }
        
        detailView.replace(FieldsConstants.CLUSTERS, JacksonUtils.transferToJsonNode(clusters));
        
        return detailView;
    }
@Test
    void testGetServiceDetail() throws NacosException {
        ServiceMetadata serviceMetadata = new ServiceMetadata();
        serviceMetadata.setProtectThreshold(0.75F);
        Mockito.when(metadataManager.getServiceMetadata(Mockito.any())).thenReturn(Optional.of(serviceMetadata));
        Mockito.when(serviceStorage.getClusters(Mockito.any())).thenReturn(Collections.singleton("C"));
        Object obj = catalogServiceV2Impl.getServiceDetail("A", "B", "C");
        ObjectNode objectNode = (ObjectNode) obj;
        assertEquals("C", objectNode.get(FieldsConstants.SERVICE).get(FieldsConstants.NAME).asText());
        assertEquals("B", objectNode.get(FieldsConstants.SERVICE).get(FieldsConstants.GROUP_NAME).asText());
        assertEquals("none", objectNode.get(FieldsConstants.SERVICE).get(FieldsConstants.SELECTOR).get("type").asText());
        assertEquals(0, objectNode.get(FieldsConstants.SERVICE).get(FieldsConstants.METADATA).size());
        assertEquals(0.75, objectNode.get(FieldsConstants.SERVICE).get(FieldsConstants.PROTECT_THRESHOLD).asDouble(), 0.1);
    }