Good stuff
This commit is contained in:
parent
9e428a0499
commit
0e81a65d62
11 changed files with 86 additions and 59 deletions
|
|
@ -5,11 +5,9 @@ import org.apache.hc.client5.http.classic.HttpClient;
|
|||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.operaton.fitpub.config.TestcontainersConfiguration;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
|
@ -22,7 +20,6 @@ import org.springframework.web.client.RestTemplate;
|
|||
@SpringBootApplication
|
||||
@EnableAsync
|
||||
@Slf4j
|
||||
@Import(TestcontainersConfiguration.class)
|
||||
public class FitPubApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
package org.operaton.fitpub.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
/**
|
||||
* Testcontainers configuration for development using Spring Boot Dev Services.
|
||||
* Automatically starts a PostgreSQL container with PostGIS extension when running in dev mode.
|
||||
*
|
||||
* This ensures development environment matches production (PostgreSQL + PostGIS).
|
||||
*
|
||||
* Only active when NOT running in production profile AND Testcontainers is on the classpath.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Profile("!prod")
|
||||
@ConditionalOnClass(PostgreSQLContainer.class)
|
||||
public class TestcontainersConfiguration {
|
||||
|
||||
/**
|
||||
* PostgreSQL container with PostGIS extension.
|
||||
* Uses postgis/postgis image which includes both PostgreSQL and PostGIS.
|
||||
*
|
||||
* @ServiceConnection automatically configures spring.datasource.* properties
|
||||
*/
|
||||
@Bean
|
||||
@ServiceConnection
|
||||
PostgreSQLContainer<?> postgresContainer() {
|
||||
return new PostgreSQLContainer<>(
|
||||
DockerImageName.parse("postgis/postgis:16-3.4")
|
||||
.asCompatibleSubstituteFor("postgres")
|
||||
)
|
||||
.withDatabaseName("fitpub")
|
||||
.withUsername("fitpub")
|
||||
.withPassword("fitpub")
|
||||
.withReuse(true); // Reuse container across runs for faster startup
|
||||
}
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ public class Actor {
|
|||
.mediaType("image/jpeg")
|
||||
.url(user.getAvatarUrl())
|
||||
.build() : null)
|
||||
.url(baseUrl + "/@" + user.getUsername())
|
||||
.url(baseUrl + "/users/" + user.getUsername())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
|||
6
src/main/resources/META-INF/spring-devtools.properties
Normal file
6
src/main/resources/META-INF/spring-devtools.properties
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Exclude Testcontainers from devtools restart
|
||||
# This allows Testcontainers to be loaded by the base classloader
|
||||
restart.exclude.testcontainers=/testcontainers[\\w\\-]*\\.jar
|
||||
restart.exclude.testcontainers-postgresql=/testcontainers-postgresql[\\w\\-]*\\.jar
|
||||
restart.exclude.docker-java=/docker-java[\\w\\-]*\\.jar
|
||||
restart.exclude.duct-tape=/duct-tape[\\w\\-]*\\.jar
|
||||
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:postgresql://localhost:5432/fitpub
|
||||
username: fitpub
|
||||
password: change_me_in_production
|
||||
# For dev: Start PostgreSQL with: docker run -d --name fitpub-postgres -p 5432:5432 -e POSTGRES_DB=fitpub -e POSTGRES_USER=fitpub -e POSTGRES_PASSWORD=fitpub postgis/postgis:16-3.4
|
||||
url: ${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/fitpub}
|
||||
username: ${SPRING_DATASOURCE_USERNAME:fitpub}
|
||||
password: ${SPRING_DATASOURCE_PASSWORD:fitpub}
|
||||
driver-class-name: org.postgresql.Driver
|
||||
|
||||
jpa:
|
||||
|
|
|
|||
|
|
@ -266,11 +266,19 @@
|
|||
|
||||
#activityTypeTabs .nav-link {
|
||||
cursor: pointer;
|
||||
color: var(--dark-color) !important;
|
||||
font-weight: 700;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#activityTypeTabs .nav-link:hover {
|
||||
color: var(--primary-color) !important;
|
||||
background-color: rgba(255, 20, 147, 0.1);
|
||||
}
|
||||
|
||||
#activityTypeTabs .nav-link.active {
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
||||
color: white;
|
||||
color: white !important;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@
|
|||
|
||||
<!-- Period Selector -->
|
||||
<div class="btn-group mb-4 w-100" role="group">
|
||||
<button type="button" class="btn btn-outline-primary active" onclick="loadTrainingLoad(30)">
|
||||
<button type="button" class="btn btn-outline-primary active" onclick="loadTrainingLoad(event, 30)">
|
||||
Last 30 Days
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary" onclick="loadTrainingLoad(60)">
|
||||
<button type="button" class="btn btn-outline-primary" onclick="loadTrainingLoad(event, 60)">
|
||||
Last 60 Days
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary" onclick="loadTrainingLoad(90)">
|
||||
<button type="button" class="btn btn-outline-primary" onclick="loadTrainingLoad(event, 90)">
|
||||
Last 90 Days
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -123,11 +123,13 @@
|
|||
card.style.backgroundColor = config.bgColor;
|
||||
}
|
||||
|
||||
async function loadTrainingLoad(days = 30) {
|
||||
async function loadTrainingLoad(event, days = 30) {
|
||||
try {
|
||||
// Update active button
|
||||
document.querySelectorAll('.btn-group button').forEach(btn => btn.classList.remove('active'));
|
||||
event.target.classList.add('active');
|
||||
// Update active button (only if called from a button click)
|
||||
if (event && event.target) {
|
||||
document.querySelectorAll('.btn-group button').forEach(btn => btn.classList.remove('active'));
|
||||
event.target.classList.add('active');
|
||||
}
|
||||
|
||||
document.getElementById('loading-spinner').style.display = 'block';
|
||||
document.getElementById('charts-content').style.display = 'none';
|
||||
|
|
@ -301,7 +303,7 @@
|
|||
return;
|
||||
}
|
||||
loadFormStatus();
|
||||
loadTrainingLoad(30);
|
||||
loadTrainingLoad(null, 30);
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
package org.operaton.fitpub.config;
|
||||
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
/**
|
||||
* Testcontainers configuration for tests.
|
||||
* Automatically starts a PostgreSQL container with PostGIS extension for integration tests.
|
||||
*/
|
||||
@TestConfiguration(proxyBeanMethods = false)
|
||||
public class TestcontainersConfiguration {
|
||||
|
||||
/**
|
||||
* PostgreSQL container with PostGIS extension for tests.
|
||||
* @ServiceConnection automatically configures the datasource from this container.
|
||||
*/
|
||||
@Bean
|
||||
@ServiceConnection
|
||||
public PostgreSQLContainer<?> postgresContainer() {
|
||||
return new PostgreSQLContainer<>(
|
||||
DockerImageName.parse("postgis/postgis:16-3.4")
|
||||
.asCompatibleSubstituteFor("postgres")
|
||||
)
|
||||
.withDatabaseName("fitpub")
|
||||
.withUsername("fitpub")
|
||||
.withPassword("fitpub")
|
||||
.withReuse(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,10 +2,12 @@ package org.operaton.fitpub.security;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.operaton.fitpub.config.TestcontainersConfiguration;
|
||||
import org.operaton.fitpub.model.entity.User;
|
||||
import org.operaton.fitpub.repository.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyFactory;
|
||||
|
|
@ -23,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||
* Test to validate that users' public and private keys match.
|
||||
*/
|
||||
@SpringBootTest
|
||||
@Import(TestcontainersConfiguration.class)
|
||||
@Slf4j
|
||||
public class KeyPairValidationTest {
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.operaton.fitpub.service;
|
|||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.operaton.fitpub.config.TestcontainersConfiguration;
|
||||
import org.operaton.fitpub.model.entity.Activity;
|
||||
import org.operaton.fitpub.model.entity.ActivityMetrics;
|
||||
import org.operaton.fitpub.model.entity.User;
|
||||
|
|
@ -11,6 +12,7 @@ import org.operaton.fitpub.repository.UserRepository;
|
|||
import org.operaton.fitpub.util.FitParser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -30,6 +32,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||
"fitpub.image.osm-tiles.enabled=true"
|
||||
})
|
||||
@ActiveProfiles("test")
|
||||
@Import(TestcontainersConfiguration.class)
|
||||
class ActivityImageServiceTest {
|
||||
|
||||
@Autowired
|
||||
|
|
|
|||
|
|
@ -55,6 +55,21 @@ class FitFileServiceTest {
|
|||
@Mock
|
||||
private ActivityMetricsRepository metricsRepository;
|
||||
|
||||
@Mock
|
||||
private PersonalRecordService personalRecordService;
|
||||
|
||||
@Mock
|
||||
private AchievementService achievementService;
|
||||
|
||||
@Mock
|
||||
private TrainingLoadService trainingLoadService;
|
||||
|
||||
@Mock
|
||||
private ActivitySummaryService activitySummaryService;
|
||||
|
||||
@Mock
|
||||
private WeatherService weatherService;
|
||||
|
||||
@Spy
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
|
|
@ -148,7 +163,9 @@ class FitFileServiceTest {
|
|||
// Assert
|
||||
assertNotNull(result);
|
||||
assertTrue(result.getTitle().contains("Run"));
|
||||
assertTrue(result.getTitle().contains(testParsedData.getStartTime().toLocalDate().toString()));
|
||||
// Title format is "[Time of Day] [Activity Type]" (e.g., "Morning Run")
|
||||
// Start time is 8:00 AM, which is "Morning"
|
||||
assertTrue(result.getTitle().contains("Morning"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue