From f76761b0278d68dda965d72dd0d594031473bd29 Mon Sep 17 00:00:00 2001 From: javgarbor2 Date: Mon, 5 May 2025 17:30:49 +0200 Subject: [PATCH 1/2] Test RemoteEnquirer Test para la clase ExtraccionMetricas que implementa la interfaz RemoteEnquirer --- .../test/model/remote/RemoteEnquirerTest.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java diff --git a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java new file mode 100644 index 00000000..5deb82da --- /dev/null +++ b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java @@ -0,0 +1,85 @@ +package us.muit.fs.a4i.test.model.remote; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.logging.Logger; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import us.muit.fs.a4i.exceptions.MetricException; +import us.muit.fs.a4i.model.entities.ReportItem; +import us.muit.fs.a4i.model.entities.ReportItemI; +import us.muit.fs.a4i.model.remote.GitHubRepositoryEnquirer; +import us.muit.fs.a4i.model.remote.RemoteEnquirer; + +class RemoteEnquirerTest { + + private static Logger log = Logger.getLogger(RemoteEnquirerTest.class.getName()); + + private RemoteEnquirer enquirer = new ExtraccionMetricas(); // Asegúrate que esta clase existe y está implementada + + + // Test que certifica que se puede obtener la métrica "totalIssues" (el resultado no es nulo, + // el nombre de la métrica coincide al completo y el valor es de tipo numérico). + + @Test + void testGetTotalIssuesMetric() throws MetricException { + String repoId = "Isabel-Roman"; // Reemplazar con un repositorio válido de prueba + + ReportItemI metric = enquirer.getMetric("totalIssues", repoId); + assertNotNull(metric, "La métrica 'totalIssues' no debe ser null"); + assertEquals("totalIssues", metric.getName()); + assertTrue(metric.getValue() instanceof Number, "El valor debe ser numérico"); + + log.info("Total Issues: " + metric.getValue()); + } + + // Test que certifica que se puede obtener la métrica "labeledIssues" (el resultado no es nulo, + // el nombre de la métrica coincide al completo y el valor es de tipo numérico). + + @Test + void testGetLabeledIssuesMetric() throws MetricException { + String repoId = "Isabel-Roman"; // Reemplazar con un repositorio válido de prueba + + ReportItemI metric = enquirer.getMetric("labeledIssues", repoId); + assertNotNull(metric, "La métrica 'labeledIssues' no debe ser null"); + assertEquals("labeledIssues", metric.getName()); + assertTrue(metric.getValue() instanceof Number, "El valor debe ser numérico"); + + log.info("Issues con etiquetas: " + metric.getValue()); + } + + + // Test que verifica que el objeto informa correctamente de las métricas que soporta (que + // la lista no es nula y que dentro de las posibilidades están "totalIssues" y "labeledIssues") + + @Test + void testGetAvailableMetrics() { + List metrics = enquirer.getAvailableMetrics(); + assertNotNull(metrics); + assertTrue(metrics.contains("totalIssues"), "Debe contener la métrica 'totalIssues'"); + assertTrue(metrics.contains("labeledIssues"), "Debe contener la métrica 'labeledIssues'"); + } + + // Test que intenta pedir una métrica que no existe, para comprobar que la excepción salta como se espera + + + @Test + void testInvalidMetricThrowsException() { + String repoId = "Isabel-Roman"; + + assertThrows(MetricException.class, () -> { + enquirer.getMetric("nonExistentMetric", repoId); + }); + } + + + // Test que verifica que el tipo de la clase está correctamente identificado como GITHUB + + @Test + void testGetRemoteType() { + assertEquals(RemoteEnquirer.RemoteType.GITHUB, enquirer.getRemoteType()); + } +} From e15fd16adef2d28039e7a6c4b57e0ed3d34afe88 Mon Sep 17 00:00:00 2001 From: pedhidtap Date: Tue, 6 May 2025 17:31:33 +0200 Subject: [PATCH 2/2] Codigo de la clase ExtraccionMetricas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Se ha desarrollado el código que implementa la interfaz de RemoteEnquirer y se ha verificado como efectivamente pasan los tests. Además se ha indicado el repositorio de la asignatura en RemoteEnquirerTest, en lugar del que venía, para obtener varios issues que medir. --- .../a4i/model/remote/ExtraccionMetricas.java | 104 ++++++++++++++++++ src/main/resources/a4iDefault.json | 10 +- .../test/model/remote/RemoteEnquirerTest.java | 5 +- 3 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java diff --git a/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java b/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java new file mode 100644 index 00000000..fa46906a --- /dev/null +++ b/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java @@ -0,0 +1,104 @@ +package us.muit.fs.a4i.model.remote; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.kohsuke.github.GHIssue; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GitHub; +import org.kohsuke.github.GitHubBuilder; + +import us.muit.fs.a4i.exceptions.MetricException; +import us.muit.fs.a4i.model.entities.ReportItemI; +import us.muit.fs.a4i.model.entities.ReportItem.ReportItemBuilder; +import us.muit.fs.a4i.model.entities.Report; +import us.muit.fs.a4i.model.entities.ReportI; + + +public class ExtraccionMetricas implements RemoteEnquirer { + + private static final List SUPPORTED_METRICS = Arrays.asList("totalIssues", "labeledIssues"); + + @Override + public ReportI buildReport(String entityId) { + try { + Report report = new Report(ReportI.ReportType.REPOSITORY, entityId); + + for (String metric : getAvailableMetrics()) { + ReportItemI item = getMetric(metric, entityId); + report.addMetric(item); + } + + return report; + + } catch (MetricException e) { + throw new RuntimeException("Error al construir el informe: " + e.getMessage(), e); + } + } + + @Override + public ReportItemI getMetric(String metricName, String entityId) throws MetricException { + if (!SUPPORTED_METRICS.contains(metricName)) { + throw new MetricException("Métrica no soportada: " + metricName); + } + + if (!entityId.contains("/")) { + entityId = entityId + "/Audit4Improve-API"; + } + + try { + GitHub github; + String token = System.getenv("GITHUB_PACKAGES"); + + if (token != null && !token.isEmpty()) { + github = new GitHubBuilder().withOAuthToken(token).build(); + } else { + github = GitHub.connectAnonymously(); + } + GHRepository repo = github.getRepository(entityId); + + int total = 0; + int etiquetados = 0; + + for (GHIssue issue : repo.getIssues(org.kohsuke.github.GHIssueState.OPEN)) { + if (!issue.isPullRequest()) { + total++; + if (!issue.getLabels().isEmpty()) { + etiquetados++; + } + } + } + + if (metricName.equals("totalIssues")) { + return new ReportItemBuilder("totalIssues", (double) total) + .source("GitHub") + .build(); + } else if (metricName.equals("labeledIssues")) { + return new ReportItemBuilder("labeledIssues", (double) etiquetados) + .source("GitHub") + .build(); + } else { + throw new MetricException("Métrica desconocida: " + metricName); + } + + } catch (IOException e) { + System.err.println("IOException: " + e.getMessage()); + throw new MetricException("Error al conectar con GitHub: " + e.getMessage()); + } catch (Exception e) { + System.err.println("Exception: " + e.getMessage()); + throw new MetricException("Error al construir ReportItem: " + e.getMessage()); + } + } + + @Override + public List getAvailableMetrics() { + return SUPPORTED_METRICS; + } + + @Override + public RemoteType getRemoteType() { + return RemoteType.GITHUB; + } + +} diff --git a/src/main/resources/a4iDefault.json b/src/main/resources/a4iDefault.json index 33cee922..74c12037 100644 --- a/src/main/resources/a4iDefault.json +++ b/src/main/resources/a4iDefault.json @@ -127,8 +127,8 @@ "unit": "issues" }, { - "name": "issues", - "type": "java.lang.Integer", + "name": "totalIssues", + "type": "java.lang.Double", "description": "Tareas totales", "unit": "issues" }, @@ -298,6 +298,12 @@ "description": "Indicador de conformidad con las convenciones en el repo", "unit": "ratio" }, + { + "name": "labeledIssues", + "type": "java.lang.Double", + "description": "Número de issues con al menos una etiqueta", + "unit": "issues" + }, { "name": "teamsBalanceI", "type": "java.lang.Double", diff --git a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java index 5deb82da..46a909c7 100644 --- a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java +++ b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java @@ -11,6 +11,7 @@ import us.muit.fs.a4i.exceptions.MetricException; import us.muit.fs.a4i.model.entities.ReportItem; import us.muit.fs.a4i.model.entities.ReportItemI; +import us.muit.fs.a4i.model.remote.ExtraccionMetricas; import us.muit.fs.a4i.model.remote.GitHubRepositoryEnquirer; import us.muit.fs.a4i.model.remote.RemoteEnquirer; @@ -26,7 +27,7 @@ class RemoteEnquirerTest { @Test void testGetTotalIssuesMetric() throws MetricException { - String repoId = "Isabel-Roman"; // Reemplazar con un repositorio válido de prueba + String repoId = "MIT-FS"; // Reemplazar con un repositorio válido de prueba ReportItemI metric = enquirer.getMetric("totalIssues", repoId); assertNotNull(metric, "La métrica 'totalIssues' no debe ser null"); @@ -41,7 +42,7 @@ void testGetTotalIssuesMetric() throws MetricException { @Test void testGetLabeledIssuesMetric() throws MetricException { - String repoId = "Isabel-Roman"; // Reemplazar con un repositorio válido de prueba + String repoId = "MIT-FS"; ReportItemI metric = enquirer.getMetric("labeledIssues", repoId); assertNotNull(metric, "La métrica 'labeledIssues' no debe ser null");