Skip to content
Open
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
61 changes: 61 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: CI/CD Pipeline

on:
push:
branches: [ "main", "master" ]
pull_request:
branches: [ "main", "master" ]

jobs:
build-test-deploy:
runs-on: ubuntu-latest

steps:
- name: Check out repository code
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: gradle

- name: Grant execute permission for gradlew
run: chmod +x gradlew
#(build)
#build and package
- name: Build and Package (JAR)
run: ./gradlew clean assemble

#(test)
#run tests and generate coverage report
- name: Run Tests and Generate Coverage Report
run: ./gradlew test jacocoTestReport

#upload jacoco test coverage artifact
- name: Upload Jacoco Test Coverage Artifact
uses: actions/upload-artifact@v4
with:
name: Code-Coverage-Report
path: build/reports/jacoco/test/html/

#upload standard unit test results
- name: Upload Standard Unit Test Results
if: always() # Upload reports even if tests fail
uses: actions/upload-artifact@v4
with:
name: Unit-Test-Results
path: build/reports/tests/test/

#(deploy)
#build docker image
- name: Build Docker Image (Deployment Staging)
run: docker build -t spring-music-app:latest .

- name: Run and Verify Docker Container
run: |
docker run -d -p 8085:8085 --name spring-music-container spring-music-app:latest
sleep 10
# Verify the container is actually running
docker ps | grep spring-music-container
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Use an official lightweight Java 17 Runtime as the base image
FROM eclipse-temurin:17-jre-alpine

# Set the working directory inside the container
WORKDIR /app

# Copy the built JAR file into the container
COPY build/libs/spring-music-1.0.jar app.jar

# Expose port 8080, which is the default port the Spring Boot app runs on
EXPOSE 8085

# Define the command to run the application when the container starts
ENTRYPOINT ["java", "-jar", "app.jar", "--server.port=8085"]
34 changes: 34 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ plugins {
id 'java'
id 'eclipse-wtp'
id 'idea'
id 'jacoco'
}

jacoco {
toolVersion = "0.8.11"
}

group = 'org.cloudfoundry.samples.music'
Expand Down Expand Up @@ -75,3 +80,32 @@ jar {
tasks.named("bootBuildImage") {
builder = "paketobuildpacks/builder-jammy-base:latest"
}

test {
testLogging {
events 'passed', 'skipped', 'failed'
}
finalizedBy jacocoTestReport
}

jacocoTestReport {
dependsOn test
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: [
'org/cloudfoundry/samples/music/config/**',
'org/cloudfoundry/samples/music/Application.class',
'org/cloudfoundry/samples/music/repositories/redis/**',
'org/cloudfoundry/samples/music/repositories/jpa/**',
'org/cloudfoundry/samples/music/repositories/mongodb/**',
'org/cloudfoundry/samples/music/repositories/AlbumRepositoryPopulator.class',
'org/cloudfoundry/samples/music/web/ErrorController.class',
'org/cloudfoundry/samples/music/web/InfoController.class'
])
}))
}
reports {
xml.required = true
html.required = true
}
}
Binary file added scc tan chi hong.docx
Binary file not shown.
2 changes: 1 addition & 1 deletion src/main/resources/static/templates/albums.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div id="albums" ng-init="init()">
<div class="page-header">
<h1>Albums</h1>
<h1>Albumss</h1>
<div>
<span> [ view as: </span>
<a href="" ng-click="setAlbumsView('grid')"><span class="glyphicon glyphicon-th"></span></a>
Expand Down
77 changes: 77 additions & 0 deletions src/test/java/org/cloudfoundry/samples/music/domain/AlbumTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.cloudfoundry.samples.music.domain;

import org.junit.Test;
import static org.junit.Assert.*;

public class AlbumTest {

@Test
public void testParameterizedConstructor() {
Album album = new Album("Test Title", "Test Artist", "2024", "Pop");
assertEquals("Test Title", album.getTitle());
assertEquals("Test Artist", album.getArtist());
assertEquals("2024", album.getReleaseYear());
assertEquals("Pop", album.getGenre());
}

@Test
public void testEmptyConstructor() {
Album album = new Album();
assertNull(album.getId());
assertNull(album.getTitle());
assertNull(album.getArtist());
assertNull(album.getReleaseYear());
assertNull(album.getGenre());
assertNull(album.getAlbumId());
assertEquals(0, album.getTrackCount());
}

@Test
public void testSetId() {
Album album = new Album();
album.setId("id123");
assertEquals("id123", album.getId());
}

@Test
public void testSetTitle() {
Album album = new Album();
album.setTitle("My Title");
assertEquals("My Title", album.getTitle());
}

@Test
public void testSetArtist() {
Album album = new Album();
album.setArtist("My Artist");
assertEquals("My Artist", album.getArtist());
}

@Test
public void testSetReleaseYear() {
Album album = new Album();
album.setReleaseYear("2025");
assertEquals("2025", album.getReleaseYear());
}

@Test
public void testSetGenre() {
Album album = new Album();
album.setGenre("Rock");
assertEquals("Rock", album.getGenre());
}

@Test
public void testSetTrackCount() {
Album album = new Album();
album.setTrackCount(12);
assertEquals(12, album.getTrackCount());
}

@Test
public void testSetAlbumId() {
Album album = new Album();
album.setAlbumId("album456");
assertEquals("album456", album.getAlbumId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.cloudfoundry.samples.music.domain;

import org.junit.Test;
import static org.junit.Assert.*;

public class ApplicationInfoTest {

@Test
public void testConstructorAndGetters() {
String[] profiles = {"mysql", "redis"};
String[] services = {"db-service", "cache-service"};

ApplicationInfo info = new ApplicationInfo(profiles, services);

assertArrayEquals(profiles, info.getProfiles());
assertArrayEquals(services, info.getServices());
}

@Test
public void testSetProfiles() {
ApplicationInfo info = new ApplicationInfo(new String[]{}, new String[]{});
String[] newProfiles = {"postgres"};
info.setProfiles(newProfiles);
assertArrayEquals(newProfiles, info.getProfiles());
}

@Test
public void testSetServices() {
ApplicationInfo info = new ApplicationInfo(new String[]{}, new String[]{});
String[] newServices = {"my-service"};
info.setServices(newServices);
assertArrayEquals(newServices, info.getServices());
}

@Test
public void testEmptyArrays() {
ApplicationInfo info = new ApplicationInfo(new String[]{}, new String[]{});
assertEquals(0, info.getProfiles().length);
assertEquals(0, info.getServices().length);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.cloudfoundry.samples.music.domain;

import org.junit.Test;
import static org.junit.Assert.*;

public class RandomIdGeneratorTest {

@Test
public void testGenerateIdReturnsNonNull() {
RandomIdGenerator generator = new RandomIdGenerator();
String id = generator.generateId();
assertNotNull(id);
}

@Test
public void testGenerateIdReturnsUUIDFormat() {
RandomIdGenerator generator = new RandomIdGenerator();
String id = generator.generateId();
// UUID format: 8-4-4-4-12 hex characters
assertTrue(id.matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"));
}

@Test
public void testGenerateIdReturnsUniqueValues() {
RandomIdGenerator generator = new RandomIdGenerator();
String id1 = generator.generateId();
String id2 = generator.generateId();
assertNotEquals(id1, id2);
}

@Test
public void testGenerateViaHibernateInterface() {
RandomIdGenerator generator = new RandomIdGenerator();
// Test the Hibernate IdentifierGenerator interface method
Object id = generator.generate(null, null);
assertNotNull(id);
assertTrue(id instanceof String);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.cloudfoundry.samples.music.web;

import org.cloudfoundry.samples.music.domain.Album;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.repository.CrudRepository;

import java.util.Arrays;
import java.util.Optional;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class AlbumControllerTest {

@Mock
private CrudRepository<Album, String> repository;

@InjectMocks
private AlbumController albumController;

@Test
public void testAlbums() {
Album album1 = new Album("Title1", "Artist1", "2020", "Pop");
Album album2 = new Album("Title2", "Artist2", "2021", "Rock");
when(repository.findAll()).thenReturn(Arrays.asList(album1, album2));

Iterable<Album> albums = albumController.albums();
assertNotNull(albums);
int count = 0;
for (Album a : albums) count++;
assertEquals(2, count);
}

@Test
public void testAdd() {
Album album = new Album("Title", "Artist", "2020", "Pop");
when(repository.save(album)).thenReturn(album);

Album added = albumController.add(album);
assertNotNull(added);
assertEquals("Title", added.getTitle());
}

@Test
public void testUpdate() {
Album album = new Album("Title", "Artist", "2020", "Pop");
when(repository.save(album)).thenReturn(album);

Album updated = albumController.update(album);
assertNotNull(updated);
assertEquals("Title", updated.getTitle());
}

@Test
public void testGetById() {
Album album = new Album("Title", "Artist", "2020", "Pop");
when(repository.findById("1")).thenReturn(Optional.of(album));

Album fetched = albumController.getById("1");
assertNotNull(fetched);
assertEquals("Title", fetched.getTitle());
}

@Test
public void testDeleteById() {
albumController.deleteById("1");
verify(repository, times(1)).deleteById("1");
}
}
Binary file added ~$c tan chi hong.docx
Binary file not shown.