From 4486e6e20635236000eff8e6f8339d7777ed7373 Mon Sep 17 00:00:00 2001 From: Gowtham-arja Date: Sun, 28 Dec 2025 16:40:19 +0530 Subject: [PATCH 1/2] #1502 Fixing NullPointerException --- .../main/java/org/eclipse/openvsx/LocalRegistryService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java index 85eecef5b..a8c7f1521 100644 --- a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java +++ b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java @@ -332,7 +332,7 @@ public QueryResultJson query(QueryRequest request) { var latest = latestVersions.get(getLatestVersionKey(ev)); var latestPreRelease = latestPreReleases.get(getLatestVersionKey(ev)); var reviewCount = reviewCounts.getOrDefault(ev.getExtension().getId(), 0L); - var preview = previewsByExtensionId.get(ev.getExtension().getId()); + var preview = previewsByExtensionId.getOrDefault(ev.getExtension().getId(), false); var extensionVersionStrings = versionStrings.get(ev.getExtension().getId()); var fileResources = fileResourcesByExtensionVersionId.getOrDefault(ev.getId(), Collections.emptyList()); return toExtensionVersionJson(ev, latest, latestPreRelease, reviewCount, preview, extensionVersionStrings, targetPlatform, fileResources, membershipsByNamespaceId); @@ -373,7 +373,7 @@ public QueryResultJson queryV2(QueryRequestV2 request) { var latest = latestVersions.get(getLatestVersionKey(ev)); var latestPreRelease = latestPreReleases.get(getLatestVersionKey(ev)); var reviewCount = reviewCounts.getOrDefault(ev.getExtension().getId(), 0L); - var preview = previewsByExtensionId.get(ev.getExtension().getId()); + var preview = previewsByExtensionId.getOrDefault(ev.getExtension().getId(), false); var fileResources = fileResourcesByExtensionVersionId.getOrDefault(ev.getId(), Collections.emptyList()); var globalLatest = addAllVersions ? latestGlobalVersions.get(ev.getExtension().getId()) : null; var globalLatestPreRelease = addAllVersions ? latestGlobalPreReleases.get(ev.getExtension().getId()) : null; From e201aaac61aead45c1538adc1b779b7837cd73ca Mon Sep 17 00:00:00 2001 From: Gowtham-arja Date: Mon, 29 Dec 2025 14:57:52 +0530 Subject: [PATCH 2/2] Added Unit test case --- .../eclipse/openvsx/LocalRegistryService.java | 4 +- .../openvsx/QueryMethodNullPreviewTest.java | 198 ++++++++++++++++++ 2 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 server/src/test/java/org/eclipse/openvsx/QueryMethodNullPreviewTest.java diff --git a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java index a8c7f1521..a6fa4001e 100644 --- a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java +++ b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java @@ -332,7 +332,7 @@ public QueryResultJson query(QueryRequest request) { var latest = latestVersions.get(getLatestVersionKey(ev)); var latestPreRelease = latestPreReleases.get(getLatestVersionKey(ev)); var reviewCount = reviewCounts.getOrDefault(ev.getExtension().getId(), 0L); - var preview = previewsByExtensionId.getOrDefault(ev.getExtension().getId(), false); + var preview = Boolean.TRUE.equals(previewsByExtensionId.getOrDefault(ev.getExtension().getId(), false)); var extensionVersionStrings = versionStrings.get(ev.getExtension().getId()); var fileResources = fileResourcesByExtensionVersionId.getOrDefault(ev.getId(), Collections.emptyList()); return toExtensionVersionJson(ev, latest, latestPreRelease, reviewCount, preview, extensionVersionStrings, targetPlatform, fileResources, membershipsByNamespaceId); @@ -373,7 +373,7 @@ public QueryResultJson queryV2(QueryRequestV2 request) { var latest = latestVersions.get(getLatestVersionKey(ev)); var latestPreRelease = latestPreReleases.get(getLatestVersionKey(ev)); var reviewCount = reviewCounts.getOrDefault(ev.getExtension().getId(), 0L); - var preview = previewsByExtensionId.getOrDefault(ev.getExtension().getId(), false); + var preview = Boolean.TRUE.equals(previewsByExtensionId.getOrDefault(ev.getExtension().getId(), false)); var fileResources = fileResourcesByExtensionVersionId.getOrDefault(ev.getId(), Collections.emptyList()); var globalLatest = addAllVersions ? latestGlobalVersions.get(ev.getExtension().getId()) : null; var globalLatestPreRelease = addAllVersions ? latestGlobalPreReleases.get(ev.getExtension().getId()) : null; diff --git a/server/src/test/java/org/eclipse/openvsx/QueryMethodNullPreviewTest.java b/server/src/test/java/org/eclipse/openvsx/QueryMethodNullPreviewTest.java new file mode 100644 index 000000000..c1596d50b --- /dev/null +++ b/server/src/test/java/org/eclipse/openvsx/QueryMethodNullPreviewTest.java @@ -0,0 +1,198 @@ +/******************************************************************************** + * Copyright (c) 2025 TypeFox and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.openvsx; + +import jakarta.persistence.EntityManager; +import org.eclipse.openvsx.cache.CacheService; +import org.eclipse.openvsx.eclipse.EclipseService; +import org.eclipse.openvsx.entities.*; +import org.eclipse.openvsx.json.QueryResultJson; +import org.eclipse.openvsx.publish.ExtensionVersionIntegrityService; +import org.eclipse.openvsx.repositories.RepositoryService; +import org.eclipse.openvsx.json.QueryRequest; +import org.eclipse.openvsx.search.SearchUtilService; +import org.eclipse.openvsx.storage.StorageUtilService; +import org.eclipse.openvsx.util.TargetPlatform; +import org.eclipse.openvsx.util.VersionService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; + +import java.time.LocalDateTime; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + +/** + * Unit tests for LocalRegistryService.query() method + * Tests null preview value handling: + * var preview = previewsByExtensionId.getOrDefault(ev.getExtension().getId(), false); + * + * When the map contains null as the value, getOrDefault returns null (not the default false) + */ +public class QueryMethodNullPreviewTest { + + private LocalRegistryService localRegistryService; + + @Mock + private EntityManager entityManager; + + @Mock + private RepositoryService repositories; + + @Mock + private ExtensionService extensions; + + @Mock + private VersionService versions; + + @Mock + private UserService users; + + @Mock + private SearchUtilService search; + + @Mock + private ExtensionValidator validator; + + @Mock + private StorageUtilService storageUtil; + + @Mock + private EclipseService eclipse; + + @Mock + private CacheService cache; + + @Mock + private ExtensionVersionIntegrityService integrityService; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + localRegistryService = new LocalRegistryService( + entityManager, + repositories, + extensions, + versions, + users, + search, + validator, + storageUtil, + eclipse, + cache, + integrityService + ); + } + + /** + * Test query method when preview value in map is explicitly null + * This tests the critical case where: + * var preview = previewsByExtensionId.getOrDefault(ev.getExtension().getId(), false); + * + * Returns null instead of false, and verifies the code handles it gracefully + */ + @Test + void testQueryMethodWithNullPreviewValue() { + // Setup test data + var namespace = createNamespace(1L, "test-namespace"); + var extension = createExtension(2L, "test-extension", namespace); + var extVersion = createExtensionVersion(3L, "1.0.0", extension); + + // Create query request + var queryRequest = new QueryRequest( + "test-namespace", + "test-extension", + null, + null, + null, + null, + false, + TargetPlatform.NAME_UNIVERSAL, + 100, + 0 + ); + + // Mock repository methods + when(repositories.findActiveVersions(any(QueryRequest.class))) + .thenReturn(new PageImpl<>(List.of(extVersion), Pageable.ofSize(100), 1)); + + // Mock preview map with NULL value for the extension + // This is the key test case - when getOrDefault returns null + Map previewMapWithNull = new HashMap<>(); + previewMapWithNull.put(extension.getId(), null); + when(repositories.findLatestVersionsIsPreview(Set.of(extension.getId()))) + .thenReturn(previewMapWithNull); + + // Mock other required methods + when(repositories.findLatestVersionForAllUrls(eq(extension), anyString(), anyBoolean(), anyBoolean())) + .thenReturn(extVersion); + + when(repositories.findVersionStringsSorted(any(Extension.class), anyString(), anyBoolean())) + .thenReturn(Collections.emptyList()); + + when(repositories.findFileResourcesByExtensionVersionIdAndType(any(), any())) + .thenReturn(Collections.emptyList()); + + when(repositories.findNamespaceMemberships(any())) + .thenReturn(Collections.emptyList()); + + when(versions.getLatest(any(List.class), anyBoolean(), anyBoolean())) + .thenReturn(extVersion); + + // Execute the query - this should not throw an exception + QueryResultJson result = localRegistryService.query(queryRequest); + + // Verify results + assertNotNull(result, "Query result should not be null even with null preview value"); + assertEquals(1, result.getExtensions().size(), "Should have one extension"); + assertNotNull(result.getExtensions().get(0), "Extension JSON should not be null"); + + // Verify the extension has the correct data + var returnedExtension = result.getExtensions().get(0); + assertEquals("test-extension", returnedExtension.getName(), "Extension name should be correct"); + assertEquals("test-namespace", returnedExtension.getNamespace(), "Extension namespace should be correct"); + } + + // Helper methods to create test entities + private Namespace createNamespace(long id, String name) { + var namespace = new Namespace(); + namespace.setId(id); + namespace.setName(name); + namespace.setPublicId(UUID.randomUUID().toString()); + return namespace; + } + + private Extension createExtension(long id, String name, Namespace namespace) { + var extension = new Extension(); + extension.setId(id); + extension.setName(name); + extension.setPublicId(UUID.randomUUID().toString()); + extension.setNamespace(namespace); + extension.setActive(true); + return extension; + } + + private ExtensionVersion createExtensionVersion(long id, String version, Extension extension) { + var extVersion = new ExtensionVersion(); + extVersion.setId(id); + extVersion.setVersion(version); + extVersion.setTargetPlatform(TargetPlatform.NAME_UNIVERSAL); + extVersion.setExtension(extension); + extVersion.setTimestamp(LocalDateTime.now()); + extVersion.setPreview(false); + return extVersion; + } +}