Big Feature and Beautifying Package

This commit is contained in:
Tim Zöller 2026-01-13 12:53:18 +01:00
parent 87da2a3861
commit 1f2ff67f38
171 changed files with 1286 additions and 663 deletions

View file

@ -0,0 +1,31 @@
package net.javahippie.fitpub;
import lombok.extern.slf4j.Slf4j;
import net.javahippie.fitpub.config.TestcontainersConfiguration;
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.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.client.RestTemplate;
/**
* Main Spring Boot application class for FitPub.
* FitPub is a federated fitness tracking platform that integrates with the Fediverse
* through the ActivityPub protocol.
*/
public class FitPubApplicationTest {
public static void main(String[] args) {
SpringApplication
.from(FitPubApplication::main)
.with(TestcontainersConfiguration.class)
.run(args);
}
}

View file

@ -0,0 +1,81 @@
package net.javahippie.fitpub.config;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.repository.UserRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
* Development data initializer that creates a demo user for testing.
* Only active when the 'dev' profile is enabled.
*/
@Configuration
@Profile("dev")
@RequiredArgsConstructor
@Slf4j
public class DevDataInitializer {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Bean
public CommandLineRunner initDemoUser() {
return args -> {
// Check if demo user already exists
if (userRepository.findByUsername("demo").isPresent()) {
log.info("Demo user already exists, skipping initialization");
return;
}
log.info("Creating demo user for development...");
try {
// Generate RSA key pair for ActivityPub
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
String publicKey = "-----BEGIN PUBLIC KEY-----\n" +
Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()) +
"\n-----END PUBLIC KEY-----";
String privateKey = "-----BEGIN PRIVATE KEY-----\n" +
Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()) +
"\n-----END PRIVATE KEY-----";
// Create demo user
User demoUser = User.builder()
.username("demo")
.email("demo@fitpub.local")
.passwordHash(passwordEncoder.encode("demo"))
.displayName("Demo User")
.bio("This is a demo account for testing FitPub features. Upload your FIT files and explore the federated fitness tracking platform!")
.publicKey(publicKey)
.privateKey(privateKey)
.build();
userRepository.save(demoUser);
log.info("=".repeat(80));
log.info("Demo user created successfully!");
log.info("Username: demo");
log.info("Password: demo");
log.info("Email: demo@fitpub.local");
log.info("=".repeat(80));
} catch (NoSuchAlgorithmException e) {
log.error("Failed to generate RSA key pair for demo user", e);
}
};
}
}

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.config;
package net.javahippie.fitpub.config;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
@ -15,6 +15,7 @@ public class TestcontainersConfiguration {
/**
* PostgreSQL container with PostGIS extension for tests.
* PostGIS image is treated as a standard PostgreSQL container.
* @ServiceConnection automatically configures the datasource from this container.
*/
@Bean
@ -24,9 +25,8 @@ public class TestcontainersConfiguration {
DockerImageName.parse("postgis/postgis:16-3.4")
.asCompatibleSubstituteFor("postgres")
)
.withDatabaseName("fitpub")
.withUsername("fitpub")
.withPassword("fitpub")
.withReuse(true);
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
}
}

View file

@ -1,16 +1,16 @@
package org.operaton.fitpub.controller;
package net.javahippie.fitpub.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.operaton.fitpub.model.dto.ActivityDTO;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.model.entity.User;
import org.operaton.fitpub.repository.ActivityRepository;
import org.operaton.fitpub.repository.UserRepository;
import org.operaton.fitpub.security.JwtTokenProvider;
import org.operaton.fitpub.config.TestcontainersConfiguration;
import net.javahippie.fitpub.model.dto.ActivityDTO;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.repository.UserRepository;
import net.javahippie.fitpub.security.JwtTokenProvider;
import net.javahippie.fitpub.config.TestcontainersConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
@ -20,6 +20,7 @@ import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.transaction.annotation.Transactional;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.math.BigDecimal;
import java.nio.file.Files;
@ -37,7 +38,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
@Transactional
@Import(TestcontainersConfiguration.class)
class ActivityControllerIntegrationTest {

View file

@ -1,21 +1,23 @@
package org.operaton.fitpub.integration;
package net.javahippie.fitpub.integration;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.javahippie.fitpub.config.TestcontainersConfiguration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.operaton.fitpub.model.entity.Follow;
import org.operaton.fitpub.model.entity.RemoteActor;
import org.operaton.fitpub.model.entity.User;
import org.operaton.fitpub.repository.FollowRepository;
import org.operaton.fitpub.repository.RemoteActorRepository;
import org.operaton.fitpub.repository.UserRepository;
import org.operaton.fitpub.security.JwtTokenProvider;
import net.javahippie.fitpub.model.entity.Follow;
import net.javahippie.fitpub.model.entity.RemoteActor;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.repository.FollowRepository;
import net.javahippie.fitpub.repository.RemoteActorRepository;
import net.javahippie.fitpub.repository.UserRepository;
import net.javahippie.fitpub.security.JwtTokenProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.ActiveProfiles;
@ -41,8 +43,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
@Transactional
@Import(TestcontainersConfiguration.class)
class FederationFollowFlowIntegrationTest {
@Autowired

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.security;
package net.javahippie.fitpub.security;
import org.junit.jupiter.api.Test;

View file

@ -1,14 +1,16 @@
package org.operaton.fitpub.security;
package net.javahippie.fitpub.security;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Disabled;
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 net.javahippie.fitpub.config.TestcontainersConfiguration;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.Transactional;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
@ -28,9 +30,10 @@ import static org.junit.jupiter.api.Assertions.*;
* Run manually when needed: mvn test -Dtest=KeyPairValidationTest
*/
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
@Import(TestcontainersConfiguration.class)
@Slf4j
@Disabled("Integration test - requires live database with user data. Run manually when needed.")
public class KeyPairValidationTest {
@Autowired

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
@ -7,14 +7,13 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.operaton.fitpub.model.entity.Achievement;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.model.entity.ActivityMetrics;
import org.operaton.fitpub.repository.AchievementRepository;
import org.operaton.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.model.entity.Achievement;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.ActivityMetrics;
import net.javahippie.fitpub.repository.AchievementRepository;
import net.javahippie.fitpub.repository.ActivityRepository;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;

View file

@ -1,22 +1,21 @@
package org.operaton.fitpub.service;
package net.javahippie.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;
import org.operaton.fitpub.repository.ActivityRepository;
import org.operaton.fitpub.repository.UserRepository;
import org.operaton.fitpub.util.FitParser;
import org.operaton.fitpub.util.ParsedActivityData;
import net.javahippie.fitpub.config.TestcontainersConfiguration;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.ActivityMetrics;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.repository.UserRepository;
import net.javahippie.fitpub.util.FitParser;
import net.javahippie.fitpub.util.ParsedActivityData;
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;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

View file

@ -1,6 +1,5 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import jakarta.persistence.EntityNotFoundException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@ -8,10 +7,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.model.entity.User;
import org.operaton.fitpub.repository.ActivityRepository;
import org.operaton.fitpub.repository.UserRepository;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.repository.UserRepository;
import org.springframework.test.util.ReflectionTestUtils;
import java.math.BigDecimal;
@ -19,7 +18,6 @@ import java.time.LocalDateTime;
import java.util.Optional;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
@ -13,14 +13,14 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.operaton.fitpub.exception.FitFileProcessingException;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.repository.ActivityMetricsRepository;
import org.operaton.fitpub.repository.ActivityRepository;
import org.operaton.fitpub.util.FitFileValidator;
import org.operaton.fitpub.util.FitParser;
import org.operaton.fitpub.util.ParsedActivityData;
import org.operaton.fitpub.util.TrackSimplifier;
import net.javahippie.fitpub.exception.FitFileProcessingException;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.repository.ActivityMetricsRepository;
import net.javahippie.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.util.FitFileValidator;
import net.javahippie.fitpub.util.FitParser;
import net.javahippie.fitpub.util.ParsedActivityData;
import net.javahippie.fitpub.util.TrackSimplifier;
import org.springframework.mock.web.MockMultipartFile;
import java.math.BigDecimal;
@ -378,7 +378,8 @@ class FitFileServiceTest {
userId,
"New Title",
"New Description",
Activity.Visibility.PUBLIC
Activity.Visibility.PUBLIC,
false
);
// Assert
@ -421,7 +422,8 @@ class FitFileServiceTest {
userId,
"New Title",
"New Description",
Activity.Visibility.PUBLIC
Activity.Visibility.PUBLIC,
false
)
);
@ -450,7 +452,8 @@ class FitFileServiceTest {
differentUserId,
"Hacked Title",
"Hacked Description",
Activity.Visibility.PUBLIC
Activity.Visibility.PUBLIC,
false
)
);
@ -492,7 +495,8 @@ class FitFileServiceTest {
userId,
"Updated Title",
"Updated Description",
Activity.Visibility.PUBLIC
Activity.Visibility.PUBLIC,
false
);
// Assert - verify updated fields

View file

@ -1,21 +1,18 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.PrecisionModel;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.model.entity.User;
import org.operaton.fitpub.model.entity.UserHeatmapGrid;
import org.operaton.fitpub.repository.ActivityRepository;
import org.operaton.fitpub.repository.UserHeatmapGridRepository;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.model.entity.UserHeatmapGrid;
import net.javahippie.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.repository.UserHeatmapGridRepository;
import java.util.*;

View file

@ -1,17 +1,16 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.model.entity.ActivityMetrics;
import org.operaton.fitpub.model.entity.PersonalRecord;
import org.operaton.fitpub.repository.PersonalRecordRepository;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.ActivityMetrics;
import net.javahippie.fitpub.model.entity.PersonalRecord;
import net.javahippie.fitpub.repository.PersonalRecordRepository;
import java.math.BigDecimal;
import java.time.LocalDateTime;

View file

@ -1,5 +1,8 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import net.javahippie.fitpub.repository.CommentRepository;
import net.javahippie.fitpub.repository.LikeRepository;
import net.javahippie.fitpub.repository.RemoteActorRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@ -7,20 +10,21 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.operaton.fitpub.model.dto.TimelineActivityDTO;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.model.entity.Follow;
import org.operaton.fitpub.model.entity.RemoteActivity;
import org.operaton.fitpub.model.entity.User;
import org.operaton.fitpub.repository.ActivityRepository;
import org.operaton.fitpub.repository.FollowRepository;
import org.operaton.fitpub.repository.RemoteActivityRepository;
import org.operaton.fitpub.repository.UserRepository;
import net.javahippie.fitpub.model.dto.TimelineActivityDTO;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.Follow;
import net.javahippie.fitpub.model.entity.RemoteActivity;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.repository.FollowRepository;
import net.javahippie.fitpub.repository.RemoteActivityRepository;
import net.javahippie.fitpub.repository.UserRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayList;
@ -54,13 +58,16 @@ class TimelineServiceTest {
private UserRepository userRepository;
@Mock
private org.operaton.fitpub.repository.LikeRepository likeRepository;
private LikeRepository likeRepository;
@Mock
private org.operaton.fitpub.repository.CommentRepository commentRepository;
private CommentRepository commentRepository;
@Mock
private org.operaton.fitpub.repository.RemoteActorRepository remoteActorRepository;
private RemoteActorRepository remoteActorRepository;
@Mock
private TimelineResultMapper timelineResultMapper;
@InjectMocks
private TimelineService timelineService;
@ -93,15 +100,20 @@ class TimelineServiceTest {
.thenReturn(follows);
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
// Mock local activities
List<Activity> localActivities = List.of(
createLocalActivity("Morning Run", LocalDateTime.now().minusHours(2))
);
Page<Activity> localActivitiesPage = new PageImpl<>(localActivities);
when(activityRepository.findByUserIdInAndVisibilityInOrderByStartedAtDesc(
anyList(), anyList(), any(Pageable.class)))
// Mock local activities using Object[] (as returned by native query)
Object[] row1 = createTimelineRow("Morning Run", LocalDateTime.now().minusHours(2));
List<Object[]> localActivityRows = new ArrayList<>();
localActivityRows.add(row1);
Page<Object[]> localActivitiesPage = new PageImpl<>(localActivityRows);
when(activityRepository.findFederatedTimelineWithStats(
anyList(), anyList(), eq(userId), any(Pageable.class)))
.thenReturn(localActivitiesPage);
// Mock the mapper
TimelineActivityDTO dto1 = createTimelineDTO("Morning Run", LocalDateTime.now().minusHours(2));
when(timelineResultMapper.mapToTimelineActivityDTO(any(Object[].class)))
.thenReturn(dto1);
// Mock remote activities - this should use publishedAt for sorting
List<RemoteActivity> remoteActivities = List.of(
createRemoteActivity("Remote Run 1", Instant.now().minusSeconds(3600)),
@ -124,8 +136,8 @@ class TimelineServiceTest {
assertFalse(result.isEmpty(), "Result should contain activities");
// Verify that both repositories were called
verify(activityRepository).findByUserIdInAndVisibilityInOrderByStartedAtDesc(
anyList(), anyList(), any(Pageable.class));
verify(activityRepository).findFederatedTimelineWithStats(
anyList(), anyList(), eq(userId), any(Pageable.class));
verify(remoteActivityRepository).findByRemoteActorUriInAndVisibilityIn(
anyList(), anyList(), any(Pageable.class));
}
@ -139,14 +151,19 @@ class TimelineServiceTest {
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
// Mock local activities only
List<Activity> localActivities = List.of(
createLocalActivity("Solo Run", LocalDateTime.now())
);
Page<Activity> localActivitiesPage = new PageImpl<>(localActivities);
when(activityRepository.findByUserIdInAndVisibilityInOrderByStartedAtDesc(
anyList(), anyList(), any(Pageable.class)))
Object[] row1 = createTimelineRow("Solo Run", LocalDateTime.now());
List<Object[]> localActivityRows = new ArrayList<>();
localActivityRows.add(row1);
Page<Object[]> localActivitiesPage = new PageImpl<>(localActivityRows);
when(activityRepository.findFederatedTimelineWithStats(
anyList(), anyList(), eq(userId), any(Pageable.class)))
.thenReturn(localActivitiesPage);
// Mock the mapper
TimelineActivityDTO dto1 = createTimelineDTO("Solo Run", LocalDateTime.now());
when(timelineResultMapper.mapToTimelineActivityDTO(any(Object[].class)))
.thenReturn(dto1);
Pageable pageable = PageRequest.of(0, 20);
// When
@ -173,12 +190,19 @@ class TimelineServiceTest {
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
// Local activity
Activity localActivity = createLocalActivity("Local Run", LocalDateTime.now().minusHours(1));
Page<Activity> localActivitiesPage = new PageImpl<>(List.of(localActivity));
when(activityRepository.findByUserIdInAndVisibilityInOrderByStartedAtDesc(
anyList(), anyList(), any(Pageable.class)))
Object[] row1 = createTimelineRow("Local Run", LocalDateTime.now().minusHours(1));
List<Object[]> localActivityRows = new ArrayList<>();
localActivityRows.add(row1);
Page<Object[]> localActivitiesPage = new PageImpl<>(localActivityRows);
when(activityRepository.findFederatedTimelineWithStats(
anyList(), anyList(), eq(userId), any(Pageable.class)))
.thenReturn(localActivitiesPage);
// Mock the mapper
TimelineActivityDTO dto1 = createTimelineDTO("Local Run", LocalDateTime.now().minusHours(1));
when(timelineResultMapper.mapToTimelineActivityDTO(any(Object[].class)))
.thenReturn(dto1);
// Remote activity
RemoteActivity remoteActivity = createRemoteActivity("Remote Run", Instant.now().minusSeconds(7200));
Page<RemoteActivity> remoteActivitiesPage = new PageImpl<>(List.of(remoteActivity));
@ -210,18 +234,48 @@ class TimelineServiceTest {
return follow;
}
private Activity createLocalActivity(String title, LocalDateTime startedAt) {
Activity activity = new Activity();
activity.setId(UUID.randomUUID());
activity.setUserId(userId);
activity.setTitle(title);
activity.setDescription("Test activity");
activity.setActivityType(Activity.ActivityType.RUN);
activity.setStartedAt(startedAt);
activity.setVisibility(Activity.Visibility.PUBLIC);
activity.setTotalDistance(java.math.BigDecimal.valueOf(5000));
activity.setTotalDurationSeconds(1800L);
return activity;
/**
* Creates an Object[] representing a row from the native query.
* The structure matches what TimelineResultMapper expects.
*/
private Object[] createTimelineRow(String title, LocalDateTime startedAt) {
UUID activityId = UUID.randomUUID();
return new Object[]{
activityId, // 0: activity_id
userId, // 1: user_id
"testuser", // 2: username
"Test User", // 3: display_name
null, // 4: avatar_url
title, // 5: title
"Test activity", // 6: description
"RUN", // 7: activity_type
startedAt, // 8: started_at
"PUBLIC", // 9: visibility
BigDecimal.valueOf(5000), // 10: total_distance
1800L, // 11: total_duration_seconds
BigDecimal.valueOf(100), // 12: elevation_gain
0L, // 13: likes_count
0L // 14: comments_count
};
}
private TimelineActivityDTO createTimelineDTO(String title, LocalDateTime startedAt) {
return TimelineActivityDTO.builder()
.id(UUID.randomUUID())
.username("testuser")
.displayName("Test User")
.title(title)
.description("Test activity")
.activityType("RUN")
.startedAt(startedAt)
.visibility("PUBLIC")
.totalDistance(5000.0)
.totalDurationSeconds(1800L)
.elevationGain(100.0)
.likesCount(0L)
.commentsCount(0L)
.isLocal(true)
.build();
}
private RemoteActivity createRemoteActivity(String title, Instant publishedAt) {

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
@ -8,14 +8,13 @@ import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.model.entity.TrainingLoad;
import org.operaton.fitpub.repository.ActivityRepository;
import org.operaton.fitpub.repository.TrainingLoadRepository;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.TrainingLoad;
import net.javahippie.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.repository.TrainingLoadRepository;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
@ -7,10 +7,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.operaton.fitpub.model.entity.User;
import org.operaton.fitpub.repository.FollowRepository;
import org.operaton.fitpub.repository.UserRepository;
import org.operaton.fitpub.security.JwtTokenProvider;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.repository.FollowRepository;
import net.javahippie.fitpub.repository.UserRepository;
import net.javahippie.fitpub.security.JwtTokenProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.util.ReflectionTestUtils;

View file

@ -1,18 +1,17 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.model.entity.WeatherData;
import org.operaton.fitpub.repository.WeatherDataRepository;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.WeatherData;
import net.javahippie.fitpub.repository.WeatherDataRepository;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.service;
package net.javahippie.fitpub.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;

View file

@ -1,18 +1,20 @@
package org.operaton.fitpub.util;
package net.javahippie.fitpub.util;
import lombok.extern.slf4j.Slf4j;
import net.javahippie.fitpub.config.TestcontainersConfiguration;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.model.entity.User;
import org.operaton.fitpub.repository.ActivityRepository;
import org.operaton.fitpub.repository.UserRepository;
import org.operaton.fitpub.service.ActivityFileService;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.User;
import net.javahippie.fitpub.repository.ActivityRepository;
import net.javahippie.fitpub.repository.UserRepository;
import net.javahippie.fitpub.service.ActivityFileService;
import java.io.IOException;
import java.io.InputStream;
@ -29,6 +31,7 @@ import static org.junit.jupiter.api.Assertions.*;
*/
@SpringBootTest
@ActiveProfiles("test")
@Import(TestcontainersConfiguration.class)
@Slf4j
@Transactional
class DatePersistenceTest {

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.util;
package net.javahippie.fitpub.util;
import com.garmin.fit.*;
import java.io.FileInputStream;

View file

@ -1,9 +1,9 @@
package org.operaton.fitpub.util;
package net.javahippie.fitpub.util;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.operaton.fitpub.exception.InvalidFitFileException;
import net.javahippie.fitpub.exception.InvalidFitFileException;
import java.io.ByteArrayInputStream;
import java.io.IOException;

View file

@ -1,10 +1,10 @@
package org.operaton.fitpub.util;
package net.javahippie.fitpub.util;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.operaton.fitpub.model.entity.Activity;
import net.javahippie.fitpub.model.entity.Activity;
import java.io.IOException;
import java.io.InputStream;

View file

@ -1,12 +1,12 @@
package org.operaton.fitpub.util;
package net.javahippie.fitpub.util;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.operaton.fitpub.model.entity.Activity;
import org.operaton.fitpub.util.ParsedActivityData.TrackPointData;
import org.operaton.fitpub.util.ParsedActivityData.ActivityMetricsData;
import net.javahippie.fitpub.model.entity.Activity;
import net.javahippie.fitpub.util.ParsedActivityData.TrackPointData;
import net.javahippie.fitpub.util.ParsedActivityData.ActivityMetricsData;
import java.io.IOException;
import java.io.InputStream;

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.util;
package net.javahippie.fitpub.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

View file

@ -1,4 +1,4 @@
package org.operaton.fitpub.util;
package net.javahippie.fitpub.util;
import com.garmin.fit.*;
import lombok.extern.slf4j.Slf4j;
@ -13,7 +13,6 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import static org.junit.jupiter.api.Assertions.*;