From 1b38b230376ca173dab62481f7da3c18896c3797 Mon Sep 17 00:00:00 2001 From: amvanbaren Date: Tue, 25 Mar 2025 14:46:10 +0200 Subject: [PATCH] cache extensionquery json --- .../org/eclipse/openvsx/ExtensionService.java | 1 + .../eclipse/openvsx/LocalRegistryService.java | 2 + .../java/org/eclipse/openvsx/UserService.java | 3 +- .../adapter/ExtensionQueryExtensionData.java | 84 +++++ .../openvsx/adapter/LocalVSCodeService.java | 302 +++++++++--------- .../adapter/VSCodeIdUpdateService.java | 23 +- .../openvsx/admin/ChangeNamespaceService.java | 1 + .../eclipse/openvsx/cache/CacheConfig.java | 22 +- .../eclipse/openvsx/cache/CacheService.java | 83 ++++- .../storage/AzureDownloadCountProcessor.java | 1 + .../adapter/LocalVSCodeServiceTest.java | 23 +- .../openvsx/adapter/VSCodeAPITest.java | 3 +- .../adapter/VSCodeIdUpdateServiceTest.java | 6 +- .../openvsx/cache/CacheServiceTest.java | 15 +- server/src/test/resources/application.yml | 2 - 15 files changed, 406 insertions(+), 165 deletions(-) create mode 100644 server/src/main/java/org/eclipse/openvsx/adapter/ExtensionQueryExtensionData.java diff --git a/server/src/main/java/org/eclipse/openvsx/ExtensionService.java b/server/src/main/java/org/eclipse/openvsx/ExtensionService.java index d968c22d6..d758df1cd 100644 --- a/server/src/main/java/org/eclipse/openvsx/ExtensionService.java +++ b/server/src/main/java/org/eclipse/openvsx/ExtensionService.java @@ -141,6 +141,7 @@ public void updateExtension(Extension extension) { cache.evictNamespaceDetails(extension); cache.evictLatestExtensionVersion(extension); cache.evictExtensionJsons(extension); + cache.evictExtensionQueryExtensionData(extension); if (extension.getVersions().stream().anyMatch(ExtensionVersion::isActive)) { // There is at least one active version => activate the extension diff --git a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java index 85eecef5b..1e28ec22f 100644 --- a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java +++ b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java @@ -694,6 +694,7 @@ public ResultJson postReview(ReviewJson review, String namespace, String extensi search.updateSearchEntry(extension); cache.evictExtensionJsons(extension); cache.evictLatestExtensionVersion(extension); + cache.evictExtensionQueryExtensionData(extension); return ResultJson.success("Added review for " + NamingUtil.toExtensionId(extension)); } @@ -721,6 +722,7 @@ public ResultJson deleteReview(String namespace, String extensionName) { search.updateSearchEntry(extension); cache.evictExtensionJsons(extension); cache.evictLatestExtensionVersion(extension); + cache.evictExtensionQueryExtensionData(extension); return ResultJson.success("Deleted review for " + NamingUtil.toExtensionId(extension)); } diff --git a/server/src/main/java/org/eclipse/openvsx/UserService.java b/server/src/main/java/org/eclipse/openvsx/UserService.java index 464ba3b8f..dc43ac681 100644 --- a/server/src/main/java/org/eclipse/openvsx/UserService.java +++ b/server/src/main/java/org/eclipse/openvsx/UserService.java @@ -170,7 +170,6 @@ public ResultJson addNamespaceMember(Namespace namespace, UserData user, String } @Transactional(rollbackOn = { ErrorResultException.class, NotFoundException.class }) - @CacheEvict(value = { CACHE_NAMESPACE_DETAILS_JSON }, key="#details.name") public ResultJson updateNamespaceDetails(NamespaceDetailsJson details, UserData user) { var namespace = repositories.findNamespace(details.getName()); if (namespace == null) { @@ -211,6 +210,8 @@ public ResultJson updateNamespaceDetails(NamespaceDetailsJson details, UserData namespace.setLogoStorageType(null); } + cache.evictNamespaceDetails(namespace); + cache.evictExtensionQueryExtensionData(namespace); return ResultJson.success("Updated details for namespace " + details.getName()); } diff --git a/server/src/main/java/org/eclipse/openvsx/adapter/ExtensionQueryExtensionData.java b/server/src/main/java/org/eclipse/openvsx/adapter/ExtensionQueryExtensionData.java new file mode 100644 index 000000000..a0880a418 --- /dev/null +++ b/server/src/main/java/org/eclipse/openvsx/adapter/ExtensionQueryExtensionData.java @@ -0,0 +1,84 @@ +/** ****************************************************************************** + * Copyright (c) 2025 Precies. Software OU 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.adapter; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +import static org.eclipse.openvsx.adapter.ExtensionQueryParam.*; + +public record ExtensionQueryExtensionData( + String publicId, + String extensionId, + String extensionName, + String displayName, + String shortDescription, + ExtensionQueryResult.Publisher publisher, + List versions, + List latestVersions, + List statistics, + List tags, + String releaseDate, + String publishedDate, + String lastUpdated, + List categories, + String preview +) { + + public record ExtensionVersion(long id, ExtensionQueryResult.ExtensionVersion data) { + public ExtensionQueryResult.ExtensionVersion toJson(int flags) { + var files = test(flags, FLAG_INCLUDE_FILES) ? data.files() : null; + var assetUri = test(flags, FLAG_INCLUDE_ASSET_URI) ? data.assetUri() : null; + var properties = test(flags, FLAG_INCLUDE_VERSION_PROPERTIES) ? data.properties() : null; + + return new ExtensionQueryResult.ExtensionVersion( + data.version(), + data.lastUpdated(), + assetUri, + assetUri, + files, + properties, + data.targetPlatform() + ); + } + } + + public ExtensionQueryResult.Extension toJson(int flags) { + var extVersionStream = Stream.empty(); + if (test(flags, FLAG_INCLUDE_LATEST_VERSION_ONLY)) { + extVersionStream = versions.stream().filter(v -> latestVersions.contains(v.id())); + } else if (test(flags, FLAG_INCLUDE_VERSIONS)) { + extVersionStream = versions.stream(); + } + + var extVersions = extVersionStream.map(v -> v.toJson(flags)).toList(); + var stats = test(flags, FLAG_INCLUDE_STATISTICS) ? statistics : Collections.emptyList(); + return new ExtensionQueryResult.Extension( + publicId, + extensionName, + displayName, + shortDescription, + publisher, + extVersions, + stats, + tags, + releaseDate, + publishedDate, + lastUpdated, + categories, + preview() + ); + } + + private static boolean test(int flags, int flag) { + return (flags & flag) != 0; + } +} diff --git a/server/src/main/java/org/eclipse/openvsx/adapter/LocalVSCodeService.java b/server/src/main/java/org/eclipse/openvsx/adapter/LocalVSCodeService.java index 854661ff7..d73e0534a 100644 --- a/server/src/main/java/org/eclipse/openvsx/adapter/LocalVSCodeService.java +++ b/server/src/main/java/org/eclipse/openvsx/adapter/LocalVSCodeService.java @@ -39,9 +39,9 @@ import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.eclipse.openvsx.adapter.ExtensionQueryParam.Criterion.*; -import static org.eclipse.openvsx.adapter.ExtensionQueryParam.*; import static org.eclipse.openvsx.adapter.ExtensionQueryResult.Extension.FLAG_PREVIEW; import static org.eclipse.openvsx.adapter.ExtensionQueryResult.ExtensionFile.*; import static org.eclipse.openvsx.adapter.ExtensionQueryResult.Property.*; @@ -102,8 +102,8 @@ public ExtensionQueryResult extensionQuery(ExtensionQueryParam param, int defaul extensionNames = Collections.emptySet(); } else { var filter = param.filters().get(0); - extensionIds = new HashSet<>(filter.findCriteria(FILTER_EXTENSION_ID)); - extensionNames = new HashSet<>(filter.findCriteria(FILTER_EXTENSION_NAME)); + extensionIds = new LinkedHashSet<>(filter.findCriteria(FILTER_EXTENSION_ID)); + extensionNames = new LinkedHashSet<>(filter.findCriteria(FILTER_EXTENSION_NAME)); queryString = filter.findCriterion(FILTER_SEARCH_TEXT); if (queryString == null) @@ -120,11 +120,23 @@ public ExtensionQueryResult extensionQuery(ExtensionQueryParam param, int defaul } Long totalCount = null; + List searchHits = Collections.emptyList(); + var usePublicIdAsKey = false; + var data = new HashMap(); List extensionsList; if (!extensionIds.isEmpty()) { - extensionsList = repositories.findActiveExtensionsByPublicId(extensionIds, BuiltInExtensionUtil.getBuiltInNamespace()); + usePublicIdAsKey = true; + var cachedData = cache.getExtensionQueryExtensionDataByPublicId(extensionIds); + data.putAll(cachedData); + + var remainingExtensionIds = extensionIds.stream().filter(id -> !cachedData.containsKey(id)).toList(); + extensionsList = repositories.findActiveExtensionsByPublicId(remainingExtensionIds, BuiltInExtensionUtil.getBuiltInNamespace()); } else if (!extensionNames.isEmpty()) { + var cachedData = cache.getExtensionQueryExtensionDataByExtensionId(extensionNames); + data.putAll(cachedData); + extensionsList = extensionNames.stream() + .filter(name -> !cachedData.containsKey(name)) .map(NamingUtil::fromExtensionId) .filter(Objects::nonNull) .filter(extensionId -> !BuiltInExtensionUtil.isBuiltIn(extensionId.namespace())) @@ -141,50 +153,36 @@ public ExtensionQueryResult extensionQuery(ExtensionQueryParam param, int defaul var searchResult = search.search(searchOptions); totalCount = searchResult.getTotalHits(); - var ids = searchResult.getHits().stream() - .map(ExtensionSearch::getId) - .collect(Collectors.toList()); - - var extensionsMap = repositories.findActiveExtensionsById(ids).stream() - .collect(Collectors.toMap(Extension::getId, e -> e)); - - // keep the same order as search results - extensionsList = ids.stream() - .map(extensionsMap::get) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } catch (ErrorResultException exc) { + searchHits = searchResult.getHits(); + } catch ( + ErrorResultException exc) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, exc.getMessage(), exc); } + + var searchIds = searchHits.stream().map(ExtensionSearch::getExtensionId).toList(); + var cachedData = cache.getExtensionQueryExtensionDataByExtensionId(searchIds); + data.putAll(cachedData); + + var ids = searchHits.stream() + .filter(hit -> !cachedData.containsKey(hit.getExtensionId())) + .map(ExtensionSearch::getId) + .collect(Collectors.toList()); + + extensionsList = repositories.findActiveExtensionsById(ids); } if(totalCount == null) { - totalCount = (long) extensionsList.size(); + totalCount = (long) (data.size() + extensionsList.size()); } - var flags = param.flags(); // when mapping the list of extensions to a map, we need to handle duplicate entries which can happen, // see https://github.com/eclipse/openvsx/issues/1394 var extensionsMap = extensionsList.stream().collect(Collectors.toMap(Extension::getId, Function.identity(), (a, b) -> a)); List allActiveExtensionVersions = repositories.findActiveExtensionVersions(extensionsMap.keySet(), targetPlatform); - List extensionVersions; - if (test(flags, FLAG_INCLUDE_LATEST_VERSION_ONLY)) { - extensionVersions = allActiveExtensionVersions.stream() - .collect(Collectors.groupingBy(ev -> ev.getExtension().getId() + "@" + ev.getTargetPlatform())) - .values() - .stream() - .map(list -> versions.getLatest(list, true)) - .collect(Collectors.toList()); - } else if (test(flags, FLAG_INCLUDE_VERSIONS) || test(flags, FLAG_INCLUDE_VERSION_PROPERTIES)) { - extensionVersions = allActiveExtensionVersions; - } else { - extensionVersions = Collections.emptyList(); - } - var comparator = Comparator.comparing(ev -> ev.getExtension().getId()) .thenComparing(ExtensionVersion.SORT_COMPARATOR); - var extensionVersionsMap = extensionVersions.stream() + var extensionVersionsMap = allActiveExtensionVersions.stream() .map(ev -> { ev.setExtension(extensionsMap.get(ev.getExtension().getId())); return ev; @@ -192,26 +190,21 @@ public ExtensionQueryResult extensionQuery(ExtensionQueryParam param, int defaul .sorted(comparator) .collect(Collectors.groupingBy(ev -> ev.getExtension().getId())); - Map> fileResources; - if (test(flags, FLAG_INCLUDE_FILES) && !extensionVersionsMap.isEmpty()) { - var types = new ArrayList<>(List.of(MANIFEST, README, LICENSE, ICON, DOWNLOAD, CHANGELOG, VSIXMANIFEST)); - if(integrityService.isEnabled()) { - types.add(DOWNLOAD_SIG); - } - - var idsMap = extensionVersionsMap.values().stream() - .flatMap(Collection::stream) - .collect(Collectors.toMap(ExtensionVersion::getId, ev -> ev)); + var latestExtensionVersionsMap = extensionVersionsMap.entrySet().stream() + .map(entry -> { + var ids = entry.getValue().stream() + .collect(Collectors.groupingBy(ExtensionVersion::getTargetPlatform)) + .values() + .stream() + .map(list -> versions.getLatest(list, true)) + .map(ExtensionVersion::getId) + .toList(); + + return Map.entry(entry.getKey(), ids); + }) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - fileResources = repositories.findFileResourcesByExtensionVersionIdAndType(idsMap.keySet(), types).stream() - .map(r -> { - r.setExtension(idsMap.get(r.getExtension().getId())); - return r; - }) - .collect(Collectors.groupingBy(fr -> fr.getExtension().getId())); - } else { - fileResources = Collections.emptyMap(); - } + var fileResources = includeFiles(allActiveExtensionVersions); var latestVersions = allActiveExtensionVersions.stream() .collect(Collectors.groupingBy(ev -> ev.getExtension().getId())) @@ -220,17 +213,36 @@ public ExtensionQueryResult extensionQuery(ExtensionQueryParam param, int defaul .map(list -> versions.getLatest(list, false)) .collect(Collectors.toMap(ev -> ev.getExtension().getId(), ev -> ev)); - var extensionQueryResults = new ArrayList(); + Function keyMapper = usePublicIdAsKey ? ExtensionQueryExtensionData::publicId : ExtensionQueryExtensionData::extensionId; for(var extension : extensionsList) { var latest = latestVersions.get(extension.getId()); var queryVersions = extensionVersionsMap.getOrDefault(extension.getId(), Collections.emptyList()).stream() - .map(extVer -> toQueryVersion(extVer, fileResources, flags)) + .map(extVer -> toQueryVersion(extVer, fileResources)) .collect(Collectors.toList()); - var queryExt = toQueryExtension(extension, latest, queryVersions, flags); - extensionQueryResults.add(queryExt); + var latestQueryVersions = latestExtensionVersionsMap.get(extension.getId()); + var queryExt = toQueryExtension(extension, latest, queryVersions, latestQueryVersions); + cache.putExtensionQueryExtensionData(queryExt); + data.put(keyMapper.apply(queryExt), queryExt); } + Stream resultStream; + if (!extensionIds.isEmpty()) { + resultStream = extensionIds.stream(); + } else if (!extensionNames.isEmpty()) { + resultStream = extensionNames.stream(); + } else if (!searchHits.isEmpty()) { + resultStream = searchHits.stream().map(ExtensionSearch::getExtensionId); + } else { + resultStream = Stream.empty(); + } + + var extensionQueryResults = resultStream + .map(data::get) + .filter(Objects::nonNull) + .map(d -> d.toJson(param.flags())) + .toList(); + return toQueryResult(extensionQueryResults, totalCount); } @@ -257,26 +269,32 @@ public ExtensionQueryResult toQueryResult(List e return new ExtensionQueryResult(List.of(resultItem)); } - private String getSortBy(int sortBy) { - switch (sortBy) { - case 4: // InstallCount - return SortBy.DOWNLOADS; - case 5: // PublishedDate - return SortBy.TIMESTAMP; - case 6: // AverageRating - return SortBy.RATING; - default: - return SortBy.RELEVANCE; + private Map> includeFiles(List extVersions) { + var types = new ArrayList<>(List.of(MANIFEST, README, LICENSE, ICON, DOWNLOAD, CHANGELOG, VSIXMANIFEST)); + if(integrityService.isEnabled()) { + types.add(DOWNLOAD_SIG); } + + var idsMap = extVersions.stream().collect(Collectors.toMap(ExtensionVersion::getId, ev -> ev)); + return repositories.findFileResourcesByExtensionVersionIdAndType(idsMap.keySet(), types).stream() + .peek(r -> r.setExtension(idsMap.get(r.getExtension().getId()))) + .collect(Collectors.groupingBy(fr -> fr.getExtension().getId())); + } + + private String getSortBy(int sortBy) { + return switch (sortBy) { + case 4 -> // InstallCount + SortBy.DOWNLOADS; + case 5 -> // PublishedDate + SortBy.TIMESTAMP; + case 6 -> // AverageRating + SortBy.RATING; + default -> SortBy.RELEVANCE; + }; } private String getSortOrder(int sortOrder) { - switch (sortOrder) { - case 1: // Ascending - return "asc"; - default: - return "desc"; - } + return sortOrder == 1 ? "asc" : "desc"; } @Observed @@ -424,8 +442,8 @@ public ResponseEntity browse(String namespaceName, String throw new NotFoundException(); } - private ExtensionQueryResult.Extension toQueryExtension(Extension extension, ExtensionVersion latest, List versions, int flags) { - var statistics = getQueryExtensionStatistics(extension, flags); + private ExtensionQueryExtensionData toQueryExtension(Extension extension, ExtensionVersion latest, List versions, List latestVersions) { + var statistics = getQueryExtensionStatistics(extension); var namespace = extension.getNamespace(); var publisher = new ExtensionQueryResult.Publisher( !StringUtils.isEmpty(namespace.getDisplayName()) ? namespace.getDisplayName() : namespace.getName(), @@ -435,13 +453,15 @@ private ExtensionQueryResult.Extension toQueryExtension(Extension extension, Ext null ); - return new ExtensionQueryResult.Extension( + return new ExtensionQueryExtensionData( extension.getPublicId(), + NamingUtil.toExtensionId(extension), extension.getName(), latest.getDisplayName(), latest.getDescription(), publisher, versions, + latestVersions, statistics, latest.getTags(), TimeUtil.toUTCString(extension.getPublishedDate()), @@ -452,89 +472,81 @@ private ExtensionQueryResult.Extension toQueryExtension(Extension extension, Ext ); } - private List getQueryExtensionStatistics(Extension extension, int flags) { + private List getQueryExtensionStatistics(Extension extension) { var statistics = new ArrayList(); - if (test(flags, FLAG_INCLUDE_STATISTICS)) { - var installStat = new ExtensionQueryResult.Statistic(STAT_INSTALL, extension.getDownloadCount()); - statistics.add(installStat); - if (extension.getAverageRating() != null) { - var avgRatingStat = new ExtensionQueryResult.Statistic(STAT_AVERAGE_RATING, extension.getAverageRating()); - statistics.add(avgRatingStat); - } - var ratingCountStat = new ExtensionQueryResult.Statistic( - STAT_RATING_COUNT, - Optional.ofNullable(extension.getReviewCount()).orElse(0L) - ); - statistics.add(ratingCountStat); + var installStat = new ExtensionQueryResult.Statistic(STAT_INSTALL, extension.getDownloadCount()); + statistics.add(installStat); + if (extension.getAverageRating() != null) { + var avgRatingStat = new ExtensionQueryResult.Statistic(STAT_AVERAGE_RATING, extension.getAverageRating()); + statistics.add(avgRatingStat); } + var ratingCountStat = new ExtensionQueryResult.Statistic( + STAT_RATING_COUNT, + Optional.ofNullable(extension.getReviewCount()).orElse(0L) + ); + statistics.add(ratingCountStat); + return statistics; } - private ExtensionQueryResult.ExtensionVersion toQueryVersion( + private ExtensionQueryExtensionData.ExtensionVersion toQueryVersion( ExtensionVersion extVer, - Map> fileResources, - int flags + Map> fileResources ) { var serverUrl = UrlUtil.getBaseUrl(); var namespaceName = extVer.getExtension().getNamespace().getName(); var extensionName = extVer.getExtension().getName(); - - String assetUri = null; - if (test(flags, FLAG_INCLUDE_ASSET_URI)) { - assetUri = UrlUtil.createApiUrl(serverUrl, "vscode", "asset", namespaceName, extensionName, extVer.getVersion()); + var assetUri = UrlUtil.createApiUrl(serverUrl, "vscode", "asset", namespaceName, extensionName, extVer.getVersion()); + + var properties = new ArrayList(); + addQueryExtensionVersionProperty(properties, PROP_BRANDING_COLOR, extVer.getGalleryColor()); + addQueryExtensionVersionProperty(properties, PROP_BRANDING_THEME, extVer.getGalleryTheme()); + addQueryExtensionVersionProperty(properties, PROP_REPOSITORY, extVer.getRepository()); + addQueryExtensionVersionProperty(properties, PROP_SPONSOR_LINK, extVer.getSponsorLink()); + addQueryExtensionVersionProperty(properties, PROP_ENGINE, getVscodeEngine(extVer)); + var dependencies = String.join(",", extVer.getDependencies()); + addQueryExtensionVersionProperty(properties, PROP_DEPENDENCY, dependencies); + var bundledExtensions = String.join(",", extVer.getBundledExtensions()); + addQueryExtensionVersionProperty(properties, PROP_EXTENSION_PACK, bundledExtensions); + var localizedLanguages = String.join(",", extVer.getLocalizedLanguages()); + addQueryExtensionVersionProperty(properties, PROP_LOCALIZED_LANGUAGES, localizedLanguages); + if (extVer.isPreRelease()) { + addQueryExtensionVersionProperty(properties, PROP_PRE_RELEASE, "true"); } - - List properties = null; - if (test(flags, FLAG_INCLUDE_VERSION_PROPERTIES)) { - properties = Lists.newArrayList(); - addQueryExtensionVersionProperty(properties, PROP_BRANDING_COLOR, extVer.getGalleryColor()); - addQueryExtensionVersionProperty(properties, PROP_BRANDING_THEME, extVer.getGalleryTheme()); - addQueryExtensionVersionProperty(properties, PROP_REPOSITORY, extVer.getRepository()); - addQueryExtensionVersionProperty(properties, PROP_SPONSOR_LINK, extVer.getSponsorLink()); - addQueryExtensionVersionProperty(properties, PROP_ENGINE, getVscodeEngine(extVer)); - var dependencies = String.join(",", extVer.getDependencies()); - addQueryExtensionVersionProperty(properties, PROP_DEPENDENCY, dependencies); - var bundledExtensions = String.join(",", extVer.getBundledExtensions()); - addQueryExtensionVersionProperty(properties, PROP_EXTENSION_PACK, bundledExtensions); - var localizedLanguages = String.join(",", extVer.getLocalizedLanguages()); - addQueryExtensionVersionProperty(properties, PROP_LOCALIZED_LANGUAGES, localizedLanguages); - if (extVer.isPreRelease()) { - addQueryExtensionVersionProperty(properties, PROP_PRE_RELEASE, "true"); - } - if (isWebExtension(extVer)) { - addQueryExtensionVersionProperty(properties, PROP_WEB_EXTENSION, "true"); - } + if (isWebExtension(extVer)) { + addQueryExtensionVersionProperty(properties, PROP_WEB_EXTENSION, "true"); } List files = null; - if(fileResources.containsKey(extVer.getId())) { - var resourcesByType = fileResources.get(extVer.getId()).stream() - .collect(Collectors.groupingBy(FileResource::getType)); - - var fileBaseUrl = UrlUtil.createApiFileBaseUrl(serverUrl, namespaceName, extensionName, extVer.getTargetPlatform(), extVer.getVersion()); - - files = Lists.newArrayList(); - addQueryExtensionVersionFile(files, FILE_MANIFEST, createFileUrl(resourcesByType.get(MANIFEST), fileBaseUrl)); - addQueryExtensionVersionFile(files, FILE_DETAILS, createFileUrl(resourcesByType.get(README), fileBaseUrl)); - addQueryExtensionVersionFile(files, FILE_LICENSE, createFileUrl(resourcesByType.get(LICENSE), fileBaseUrl)); - addQueryExtensionVersionFile(files, FILE_ICON, createFileUrl(resourcesByType.get(ICON), fileBaseUrl)); - addQueryExtensionVersionFile(files, FILE_VSIX, createFileUrl(resourcesByType.get(DOWNLOAD), fileBaseUrl)); - addQueryExtensionVersionFile(files, FILE_CHANGELOG, createFileUrl(resourcesByType.get(CHANGELOG), fileBaseUrl)); - addQueryExtensionVersionFile(files, FILE_VSIXMANIFEST, createFileUrl(resourcesByType.get(VSIXMANIFEST), fileBaseUrl)); - addQueryExtensionVersionFile(files, FILE_SIGNATURE, createFileUrl(resourcesByType.get(DOWNLOAD_SIG), fileBaseUrl)); - if(resourcesByType.containsKey(DOWNLOAD_SIG)) { - addQueryExtensionVersionFile(files, FILE_PUBLIC_KEY, UrlUtil.getPublicKeyUrl(extVer)); - } + var resourcesByType = fileResources.get(extVer.getId()).stream() + .collect(Collectors.groupingBy(FileResource::getType)); + + var fileBaseUrl = UrlUtil.createApiFileBaseUrl(serverUrl, namespaceName, extensionName, extVer.getTargetPlatform(), extVer.getVersion()); + + files = Lists.newArrayList(); + addQueryExtensionVersionFile(files, FILE_MANIFEST, createFileUrl(resourcesByType.get(MANIFEST), fileBaseUrl)); + addQueryExtensionVersionFile(files, FILE_DETAILS, createFileUrl(resourcesByType.get(README), fileBaseUrl)); + addQueryExtensionVersionFile(files, FILE_LICENSE, createFileUrl(resourcesByType.get(LICENSE), fileBaseUrl)); + addQueryExtensionVersionFile(files, FILE_ICON, createFileUrl(resourcesByType.get(ICON), fileBaseUrl)); + addQueryExtensionVersionFile(files, FILE_VSIX, createFileUrl(resourcesByType.get(DOWNLOAD), fileBaseUrl)); + addQueryExtensionVersionFile(files, FILE_CHANGELOG, createFileUrl(resourcesByType.get(CHANGELOG), fileBaseUrl)); + addQueryExtensionVersionFile(files, FILE_VSIXMANIFEST, createFileUrl(resourcesByType.get(VSIXMANIFEST), fileBaseUrl)); + addQueryExtensionVersionFile(files, FILE_SIGNATURE, createFileUrl(resourcesByType.get(DOWNLOAD_SIG), fileBaseUrl)); + if(resourcesByType.containsKey(DOWNLOAD_SIG)) { + addQueryExtensionVersionFile(files, FILE_PUBLIC_KEY, UrlUtil.getPublicKeyUrl(extVer)); } - return new ExtensionQueryResult.ExtensionVersion( - extVer.getVersion(), - TimeUtil.toUTCString(extVer.getTimestamp()), - assetUri, - assetUri, - files, - properties, - extVer.getTargetPlatform() + return new ExtensionQueryExtensionData.ExtensionVersion( + extVer.getId(), + new ExtensionQueryResult.ExtensionVersion( + extVer.getVersion(), + TimeUtil.toUTCString(extVer.getTimestamp()), + assetUri, + assetUri, + files, + properties, + extVer.getTargetPlatform() + ) ); } @@ -563,8 +575,4 @@ private String getVscodeEngine(ExtensionVersion extVer) { private boolean isWebExtension(ExtensionVersion extVer) { return extVer.getExtensionKind() != null && extVer.getExtensionKind().contains("web"); } - - private boolean test(int flags, int flag) { - return (flags & flag) != 0; - } } diff --git a/server/src/main/java/org/eclipse/openvsx/adapter/VSCodeIdUpdateService.java b/server/src/main/java/org/eclipse/openvsx/adapter/VSCodeIdUpdateService.java index 8c4192365..ef8933588 100644 --- a/server/src/main/java/org/eclipse/openvsx/adapter/VSCodeIdUpdateService.java +++ b/server/src/main/java/org/eclipse/openvsx/adapter/VSCodeIdUpdateService.java @@ -10,6 +10,7 @@ package org.eclipse.openvsx.adapter; import org.apache.commons.lang3.StringUtils; +import org.eclipse.openvsx.cache.CacheService; import org.eclipse.openvsx.entities.Extension; import org.eclipse.openvsx.repositories.RepositoryService; import org.eclipse.openvsx.util.BuiltInExtensionUtil; @@ -27,10 +28,12 @@ public class VSCodeIdUpdateService { private final RepositoryService repositories; private final VSCodeIdService service; + private final CacheService cache; - public VSCodeIdUpdateService(RepositoryService repositories, VSCodeIdService service) { + public VSCodeIdUpdateService(RepositoryService repositories, VSCodeIdService service, CacheService cache) { this.repositories = repositories; this.service = service; + this.cache = cache; } public void update(String namespaceName, String extensionName) { @@ -54,6 +57,9 @@ public void update(String namespaceName, String extensionName) { if(!namespaceUpdates.isEmpty()) { repositories.updateNamespacePublicIds(namespaceUpdates); } + if(!extensionUpdates.isEmpty() || !namespaceUpdates.isEmpty()) { + cache.evictExtensionQueryExtensionData(extension); + } } private void updateExtensionPublicId(Extension extension, Map updates, boolean mustUpdate) { @@ -106,6 +112,8 @@ private void updateNamespacePublicId(Extension extension, Map upda public void updateAll() { LOGGER.debug("DAILY UPDATE ALL"); var extensions = repositories.findAllPublicIds(); + var extensionMap = extensions.stream().collect(Collectors.toMap(e -> e.getId(), e -> e)); + var namespaceMap = extensions.stream().collect(Collectors.toMap(e -> e.getNamespace().getId(), e -> e, (id1, id2) -> id1)); var extensionPublicIdsMap = extensions.stream() .filter(e -> StringUtils.isNotEmpty(e.getPublicId())) .collect(Collectors.toMap(e -> e.getId(), e -> e.getPublicId())); @@ -152,6 +160,12 @@ public void updateAll() { LOGGER.debug("{}: {}", entry.getKey(), entry.getValue()); } + var changedExtensions = changedExtensionPublicIds.keySet().stream() + .map(extensionMap::get) + .filter(Objects::nonNull) + .toList(); + + cache.evictExtensionQueryExtensionData(changedExtensions); repositories.updateExtensionPublicIds(changedExtensionPublicIds); } @@ -164,6 +178,13 @@ public void updateAll() { LOGGER.debug("{}: {}", entry.getKey(), entry.getValue()); } + var changedExtensions = changedNamespacePublicIds.keySet().stream() + .map(namespaceMap::get) + .filter(Objects::nonNull) + .filter(e -> !changedExtensionPublicIds.containsKey(e.getId())) + .toList(); + + cache.evictExtensionQueryExtensionData(changedExtensions); repositories.updateNamespacePublicIds(changedNamespacePublicIds); } } diff --git a/server/src/main/java/org/eclipse/openvsx/admin/ChangeNamespaceService.java b/server/src/main/java/org/eclipse/openvsx/admin/ChangeNamespaceService.java index 6fe7d1ed5..2483dee77 100644 --- a/server/src/main/java/org/eclipse/openvsx/admin/ChangeNamespaceService.java +++ b/server/src/main/java/org/eclipse/openvsx/admin/ChangeNamespaceService.java @@ -55,6 +55,7 @@ public void changeNamespaceInDatabase( for(var extension : extensions) { cache.evictExtensionJsons(extension); cache.evictLatestExtensionVersion(extension); + cache.evictExtensionQueryExtensionData(extension); } if(createNewNamespace) { diff --git a/server/src/main/java/org/eclipse/openvsx/cache/CacheConfig.java b/server/src/main/java/org/eclipse/openvsx/cache/CacheConfig.java index 777d0527a..978de309d 100644 --- a/server/src/main/java/org/eclipse/openvsx/cache/CacheConfig.java +++ b/server/src/main/java/org/eclipse/openvsx/cache/CacheConfig.java @@ -162,7 +162,11 @@ public JCacheCacheManager caffeineCacheManager( @Value("${ovsx.caching.malicious-extensions.max-size:1}") long maliciousExtensionsMaxSize, @Value("${ovsx.caching.rate-limiting.name:buckets}") String rateLimitingCacheName, @Value("${ovsx.caching.rate-limiting.tti:PT1H}") Duration rateLimitingTti, - @Value("${ovsx.caching.rate-limiting.max-size:1024}") long rateLimitingMaxSize + @Value("${ovsx.caching.rate-limiting.max-size:1024}") long rateLimitingMaxSize, + @Value("${ovsx.caching.extensionquery-ids.ttl:PT1H}") Duration extensionQueryIdsTtl, + @Value("${ovsx.caching.extensionquery-ids.max-size:1024}") long extensionQueryIdsMaxSize, + @Value("${ovsx.caching.extensionquery-results.ttl:PT1H}") Duration extensionQueryResultsTtl, + @Value("${ovsx.caching.extensionquery-results.max-size:1024}") long extensionQueryResultsMaxSize ) { logger.info("Configure Caffeine cache manager"); var averageReviewRatingCache = createCaffeineConfiguration(averageReviewRatingTtl, averageReviewRatingMaxSize, false); @@ -173,6 +177,8 @@ public JCacheCacheManager caffeineCacheManager( var sitemapCache = createCaffeineConfiguration(sitemapTtl, sitemapMaxSize, false); var maliciousExtensionsCache = createCaffeineConfiguration(maliciousExtensionsTtl, maliciousExtensionsMaxSize, false); var rateLimitingCache = createCaffeineConfiguration(rateLimitingTti, rateLimitingMaxSize, true); + var extensionQueryIdsCache = createCaffeineConfiguration(extensionQueryIdsTtl, extensionQueryIdsMaxSize, false); + var extensionQueryResultsCache = createCaffeineConfiguration(extensionQueryResultsTtl, extensionQueryResultsMaxSize, false); var cacheManager = new CacheManagerImpl( new CaffeineCachingProvider(), @@ -190,6 +196,8 @@ public JCacheCacheManager caffeineCacheManager( cacheManager.createCache(CACHE_SITEMAP, sitemapCache); cacheManager.createCache(CACHE_MALICIOUS_EXTENSIONS, maliciousExtensionsCache); cacheManager.createCache(rateLimitingCacheName, rateLimitingCache); + cacheManager.createCache(CACHE_EXTENSIONQUERY_EXTENSION_IDS, extensionQueryIdsCache); + cacheManager.createCache(CACHE_EXTENSIONQUERY_RESULTS, extensionQueryResultsCache); return new JCacheCacheManager(cacheManager); } @@ -216,7 +224,9 @@ public CacheManager redisCacheManager( @Value("${ovsx.caching.extension-json.ttl:PT1H}") Duration extensionJsonTtl, @Value("${ovsx.caching.latest-extension-version.ttl:PT1H}") Duration latestExtensionVersionTtl, @Value("${ovsx.caching.sitemap.ttl:PT1H}") Duration sitemapTtl, - @Value("${ovsx.caching.malicious-extensions.ttl:P3D}") Duration maliciousExtensionsTtl + @Value("${ovsx.caching.malicious-extensions.ttl:P3D}") Duration maliciousExtensionsTtl, + @Value("${ovsx.caching.extensionquery-ids.ttl:PT1H}") Duration extensionQueryIdsTtl, + @Value("${ovsx.caching.extensionquery-results.ttl:PT1H}") Duration extensionQueryResultsTtl ) { logger.info("Configure Redis cache manager"); var extensionVersionMapper = JsonMapper.builder() @@ -252,6 +262,14 @@ public CacheManager redisCacheManager( CACHE_MALICIOUS_EXTENSIONS, redisCacheConfig(new GenericJackson2JsonRedisSerializer(), maliciousExtensionsTtl) ) + .withCacheConfiguration( + CACHE_EXTENSIONQUERY_EXTENSION_IDS, + redisCacheConfig(new GenericJackson2JsonRedisSerializer(), extensionQueryIdsTtl) + ) + .withCacheConfiguration( + CACHE_EXTENSIONQUERY_RESULTS, + redisCacheConfig(new GenericJackson2JsonRedisSerializer(), extensionQueryResultsTtl) + ) .build(); } diff --git a/server/src/main/java/org/eclipse/openvsx/cache/CacheService.java b/server/src/main/java/org/eclipse/openvsx/cache/CacheService.java index 394d600f2..a6f31ef6e 100644 --- a/server/src/main/java/org/eclipse/openvsx/cache/CacheService.java +++ b/server/src/main/java/org/eclipse/openvsx/cache/CacheService.java @@ -10,15 +10,19 @@ package org.eclipse.openvsx.cache; import io.micrometer.observation.annotation.Observed; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.openvsx.adapter.ExtensionQueryExtensionData; import org.eclipse.openvsx.entities.*; import org.eclipse.openvsx.repositories.RepositoryService; +import org.eclipse.openvsx.util.NamingUtil; import org.eclipse.openvsx.util.TargetPlatform; import org.eclipse.openvsx.util.VersionAlias; import org.springframework.cache.CacheManager; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; @Component public class CacheService { @@ -33,6 +37,8 @@ public class CacheService { public static final String CACHE_AVERAGE_REVIEW_RATING = "average.review.rating"; public static final String CACHE_SITEMAP = "sitemap"; public static final String CACHE_MALICIOUS_EXTENSIONS = "malicious.extensions"; + public static final String CACHE_EXTENSIONQUERY_EXTENSION_IDS = "vscode.extensionquery.ids"; + public static final String CACHE_EXTENSIONQUERY_RESULTS = "vscode.extensionquery.results"; public static final String GENERATOR_EXTENSION_JSON = "extensionJsonCacheKeyGenerator"; public static final String GENERATOR_LATEST_EXTENSION_VERSION = "latestExtensionVersionCacheKeyGenerator"; @@ -187,4 +193,77 @@ public void evictWebResourceFile(String namespaceName, String extensionName, Str cache.evict(filesCacheKeyGenerator.generate(namespaceName, extensionName, targetPlatform, version, path)); } + + public Map getExtensionQueryExtensionDataByPublicId(Set publicIds) { + var cache = cacheManager.getCache(CACHE_EXTENSIONQUERY_EXTENSION_IDS); + if(cache == null) { + return Collections.emptyMap(); + } + + var extensionIds = publicIds.stream() + .map(publicId -> cache.get(publicId, String.class)) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + return getExtensionQueryExtensionDataByExtensionId(extensionIds, ExtensionQueryExtensionData::publicId); + } + + public Map getExtensionQueryExtensionDataByExtensionId(Collection extensionIds) { + return getExtensionQueryExtensionDataByExtensionId(extensionIds, ExtensionQueryExtensionData::extensionId); + } + + private Map getExtensionQueryExtensionDataByExtensionId(Collection extensionIds, Function keyMapper) { + var cache = cacheManager.getCache(CACHE_EXTENSIONQUERY_RESULTS); + if(cache == null) { + return Collections.emptyMap(); + } + + return extensionIds.stream() + .map(extensionId -> cache.get(extensionId, ExtensionQueryExtensionData.class)) + .filter(Objects::nonNull) + .collect(Collectors.toMap(keyMapper, d -> d)); + } + + public void putExtensionQueryExtensionData(ExtensionQueryExtensionData data) { + var resultsCache = cacheManager.getCache(CACHE_EXTENSIONQUERY_RESULTS); + if(resultsCache == null) { + return; + } + + resultsCache.put(data.extensionId(), data); + var mappingCache = cacheManager.getCache(CACHE_EXTENSIONQUERY_EXTENSION_IDS); + if(mappingCache == null) { + return; + } + + mappingCache.put(data.publicId(), data.extensionId()); + } + + public void evictExtensionQueryExtensionData(Namespace namespace) { + evictExtensionQueryExtensionData(namespace.getExtensions()); + } + + public void evictExtensionQueryExtensionData(List extensions) { + var resultsCache = cacheManager.getCache(CACHE_EXTENSIONQUERY_RESULTS); + var mappingCache = cacheManager.getCache(CACHE_EXTENSIONQUERY_EXTENSION_IDS); + extensions.forEach(e -> { + if(resultsCache != null) { + resultsCache.evictIfPresent(NamingUtil.toExtensionId(e)); + } + if(mappingCache != null && StringUtils.isNotEmpty(e.getPublicId())) { + mappingCache.evictIfPresent(e.getPublicId()); + } + }); + } + + public void evictExtensionQueryExtensionData(Extension extension) { + var resultsCache = cacheManager.getCache(CACHE_EXTENSIONQUERY_RESULTS); + var mappingCache = cacheManager.getCache(CACHE_EXTENSIONQUERY_EXTENSION_IDS); + if(resultsCache != null) { + resultsCache.evictIfPresent(NamingUtil.toExtensionId(extension)); + } + if(mappingCache != null && StringUtils.isNotEmpty(extension.getPublicId())) { + mappingCache.evictIfPresent(extension.getPublicId()); + } + } } diff --git a/server/src/main/java/org/eclipse/openvsx/storage/AzureDownloadCountProcessor.java b/server/src/main/java/org/eclipse/openvsx/storage/AzureDownloadCountProcessor.java index 2349428bf..3c73431bb 100644 --- a/server/src/main/java/org/eclipse/openvsx/storage/AzureDownloadCountProcessor.java +++ b/server/src/main/java/org/eclipse/openvsx/storage/AzureDownloadCountProcessor.java @@ -95,6 +95,7 @@ public void evictCaches(List extensions) { extension = entityManager.merge(extension); cache.evictExtensionJsons(extension); cache.evictLatestExtensionVersion(extension); + cache.evictExtensionQueryExtensionData(extension); })); } diff --git a/server/src/test/java/org/eclipse/openvsx/adapter/LocalVSCodeServiceTest.java b/server/src/test/java/org/eclipse/openvsx/adapter/LocalVSCodeServiceTest.java index 0da5dfe69..c6bc4336c 100644 --- a/server/src/test/java/org/eclipse/openvsx/adapter/LocalVSCodeServiceTest.java +++ b/server/src/test/java/org/eclipse/openvsx/adapter/LocalVSCodeServiceTest.java @@ -11,14 +11,11 @@ import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.eclipse.openvsx.cache.CacheService; -import org.eclipse.openvsx.entities.Extension; -import org.eclipse.openvsx.entities.ExtensionVersion; -import org.eclipse.openvsx.entities.Namespace; -import org.eclipse.openvsx.entities.SignatureKeyPair; +import org.eclipse.openvsx.entities.*; import org.eclipse.openvsx.publish.ExtensionVersionIntegrityService; import org.eclipse.openvsx.repositories.RepositoryService; import org.eclipse.openvsx.search.SearchUtilService; -import org.eclipse.openvsx.storage.*; +import org.eclipse.openvsx.storage.StorageUtilService; import org.eclipse.openvsx.util.VersionService; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -32,9 +29,11 @@ import java.time.LocalDateTime; import java.util.Collections; import java.util.List; +import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.openvsx.adapter.ExtensionQueryParam.*; +import static org.eclipse.openvsx.adapter.ExtensionQueryParam.Criterion; +import static org.eclipse.openvsx.entities.FileResource.*; import static org.mockito.ArgumentMatchers.*; @ExtendWith(SpringExtension.class) @@ -113,6 +112,18 @@ private ExtensionVersion mockExtensionVersion(Extension extension, long id, Stri keyPair.setPublicId("123-456-789"); extVersion.setSignatureKeyPair(keyPair); + var resourceTypes = List.of(MANIFEST, README, LICENSE, ICON, DOWNLOAD, CHANGELOG, VSIXMANIFEST); + var resources = resourceTypes.stream() + .map(type -> { + var resource = new FileResource(); + resource.setExtension(extVersion); + resource.setType(type); + resource.setName(type); + return resource; + }).toList(); + + Mockito.when(repositories.findFileResourcesByExtensionVersionIdAndType(Set.of(extVersion.getId()), resourceTypes)).thenReturn(resources); + return extVersion; } diff --git a/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java b/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java index 7e9e901cc..b29c4896b 100644 --- a/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java @@ -686,6 +686,7 @@ private Extension mockSearch(String targetPlatform, String namespaceName, boolea var builtInExtensionNamespace = "vscode"; var entry1 = new ExtensionSearch(); entry1.setId(1); + entry1.setExtensionId("redhat.vscode-yaml"); List searchHits = !builtInExtensionNamespace.equals(namespaceName) ? Collections.singletonList(entry1) : Collections.emptyList(); @@ -717,7 +718,7 @@ private Extension mockSearch(String targetPlatform, String namespaceName, boolea Mockito.when(repositories.findActiveExtensionsById(List.of(entry1.getId()))) .thenReturn(results); - var publicIds = Set.of(extension.getPublicId()); + var publicIds = List.of(extension.getPublicId()); Mockito.when(repositories.findActiveExtensionsByPublicId(publicIds, builtInExtensionNamespace)) .thenReturn(results); diff --git a/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeIdUpdateServiceTest.java b/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeIdUpdateServiceTest.java index 1af76058a..b0d61da1f 100644 --- a/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeIdUpdateServiceTest.java +++ b/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeIdUpdateServiceTest.java @@ -9,6 +9,7 @@ * ****************************************************************************** */ package org.eclipse.openvsx.adapter; +import org.eclipse.openvsx.cache.CacheService; import org.eclipse.openvsx.entities.Extension; import org.eclipse.openvsx.entities.Namespace; import org.eclipse.openvsx.repositories.RepositoryService; @@ -26,6 +27,7 @@ import java.util.UUID; @ExtendWith(SpringExtension.class) +@MockitoBean( types = { CacheService.class }) class VSCodeIdUpdateServiceTest { @MockitoBean @@ -609,8 +611,8 @@ void testUpdateDuplicateRecursive() throws InterruptedException { @TestConfiguration static class TestConfig { @Bean - VSCodeIdUpdateService vsCodeIdUpdateService(RepositoryService repositories, VSCodeIdService service) { - return new VSCodeIdUpdateService(repositories, service); + VSCodeIdUpdateService vsCodeIdUpdateService(RepositoryService repositories, VSCodeIdService service, CacheService cache) { + return new VSCodeIdUpdateService(repositories, service, cache); } } } diff --git a/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java b/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java index e6d75e410..dd984b004 100644 --- a/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java +++ b/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java @@ -22,9 +22,11 @@ import org.eclipse.openvsx.security.IdPrincipal; import org.eclipse.openvsx.util.TempFile; import org.eclipse.openvsx.util.TimeUtil; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.security.authentication.TestingAuthenticationToken; @@ -39,8 +41,11 @@ import java.time.LocalDateTime; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; import static org.eclipse.openvsx.cache.CacheService.CACHE_EXTENSION_JSON; +import static org.eclipse.openvsx.cache.CacheService.CACHE_AVERAGE_REVIEW_RATING; import static org.eclipse.openvsx.entities.FileResource.DOWNLOAD; import static org.eclipse.openvsx.entities.FileResource.STORAGE_LOCAL; import static org.junit.jupiter.api.Assertions.*; @@ -70,6 +75,14 @@ class CacheServiceTest { @Autowired RepositoryService repositories; + @BeforeEach + void beforeEach() { + Stream.of(CACHE_EXTENSION_JSON, CACHE_AVERAGE_REVIEW_RATING) + .map(name -> cache.getCache(name)) + .filter(Objects::nonNull) + .forEach(Cache::clear); + } + @Test @Transactional void testGetExtension() throws IOException { @@ -301,7 +314,7 @@ void testAverageReviewRating() throws IOException { // returns cached value assertEquals(0L, repositories.getAverageReviewRating()); - cache.getCache(CacheService.CACHE_AVERAGE_REVIEW_RATING).clear(); + cache.getCache(CACHE_AVERAGE_REVIEW_RATING).clear(); // returns new value from database assertEquals(3L, repositories.getAverageReviewRating()); diff --git a/server/src/test/resources/application.yml b/server/src/test/resources/application.yml index ed7ebd479..4197ad43c 100644 --- a/server/src/test/resources/application.yml +++ b/server/src/test/resources/application.yml @@ -39,8 +39,6 @@ org: allow-anonymous-data-usage: false ovsx: - redis: - embedded: true storage: local: directory: /tmp