Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-cache'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
}

spotless {
Expand Down
3 changes: 3 additions & 0 deletions backend/src/main/java/com/wikipediafinder/backend/BFS.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.wikipediafinder.backend.interfaces.BFSInterface;
import java.util.*;
import java.util.function.Function;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
Expand Down Expand Up @@ -32,6 +33,7 @@ public class BFS implements BFSInterface {
* @throws IllegalArgumentException if {@code start} or {@code end} is null
*/
@Override
@Cacheable(value = "pathCache", key = "#start.URL + '->' + #end.URL")
public List<String> getPath(PageNode start, PageNode end) {
return getPath(start, end, DEFAULT_FACTORY);
}
Expand Down Expand Up @@ -115,6 +117,7 @@ public List<String> getPath(
* @throws IllegalArgumentException if {@code start} or {@code end} is null
*/
@Override
@Cacheable(value = "pathStatsCache", key = "#start.URL + '->' + #end.URL")
public BFSResult getPathWithStats(PageNode start, PageNode end) {
return getPathWithStats(start, end, DEFAULT_FACTORY);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import com.wikipediafinder.backend.interfaces.WikipediaFinderApplicationInterface;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/** Main Spring Boot application class for Wikipedia path finder. */
@SpringBootApplication
@EnableCaching
public class WikipediaFinderApplication implements WikipediaFinderApplicationInterface {

/**
Expand Down
4 changes: 4 additions & 0 deletions backend/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
server.port=${PORT:8080}

# Cache configuration
spring.cache.cache-names=pathCache,pathStatsCache
spring.cache.caffeine.spec=maximumSize=1000,expireAfterWrite=1h
106 changes: 106 additions & 0 deletions backend/src/test/java/com/wikipediafinder/backend/CachingTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.wikipediafinder.backend;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cache.CacheManager;

/**
* Integration test to verify that caching is working correctly for BFS operations. Verifies that
* the cache manager is properly configured with the expected caches.
*/
@SpringBootTest
public class CachingTest {

@Autowired private BFS bfs;

@Autowired private CacheManager cacheManager;

@Test
public void testCacheManagerIsConfigured() {
assertNotNull(cacheManager, "CacheManager should be configured");
assertNotNull(cacheManager.getCache("pathCache"), "pathCache should exist");
assertNotNull(cacheManager.getCache("pathStatsCache"), "pathStatsCache should exist");
}

@Test
public void testCachingWorksForGetPath() {
// Clear cache before test
cacheManager.getCache("pathCache").clear();

PageNode start = new PageNode("https://en.wikipedia.org/wiki/Test_A");
PageNode end = new PageNode("https://en.wikipedia.org/wiki/Test_B");

// First call - cache miss, will compute and store
bfs.getPath(start, end);

// Verify cache entry exists after first call
String cacheKey = start.getURL() + "->" + end.getURL();
assertNotNull(
cacheManager.getCache("pathCache").get(cacheKey),
"Cache should contain entry for the path after first call");

// Second call - cache hit, should return cached result
bfs.getPath(start, end);

// Verify cache still contains the entry
assertNotNull(
cacheManager.getCache("pathCache").get(cacheKey),
"Cache should still contain entry after second call");
}

@Test
public void testCachingWorksForGetPathWithStats() {
// Clear cache before test
cacheManager.getCache("pathStatsCache").clear();

PageNode start = new PageNode("https://en.wikipedia.org/wiki/Test_C");
PageNode end = new PageNode("https://en.wikipedia.org/wiki/Test_D");

// First call - cache miss
BFSResult result1 = bfs.getPathWithStats(start, end);

// Second call - should use cache
BFSResult result2 = bfs.getPathWithStats(start, end);

// Verify cache entry exists
String cacheKey = start.getURL() + "->" + end.getURL();
assertNotNull(
cacheManager.getCache("pathStatsCache").get(cacheKey),
"Cache should contain entry for the path with stats");

// Results should be equal (content comparison)
assertEquals(result1.getPath(), result2.getPath(), "Cached result path should match");
assertEquals(
result1.getNodesExplored(),
result2.getNodesExplored(),
"Cached result nodes explored should match");
}

@Test
public void testCacheDifferentParameters() {
// Clear cache before test
cacheManager.getCache("pathCache").clear();

PageNode start1 = new PageNode("https://en.wikipedia.org/wiki/Test_E");
PageNode end1 = new PageNode("https://en.wikipedia.org/wiki/Test_F");
PageNode start2 = new PageNode("https://en.wikipedia.org/wiki/Test_G");
PageNode end2 = new PageNode("https://en.wikipedia.org/wiki/Test_H");

// Make calls with different parameters
bfs.getPath(start1, end1);
bfs.getPath(start2, end2);

// Verify both entries are cached separately
String cacheKey1 = start1.getURL() + "->" + end1.getURL();
String cacheKey2 = start2.getURL() + "->" + end2.getURL();

assertNotNull(
cacheManager.getCache("pathCache").get(cacheKey1), "Cache should contain first path entry");
assertNotNull(
cacheManager.getCache("pathCache").get(cacheKey2),
"Cache should contain second path entry");
}
}