From 8c06bcdad6652fa550c082f3fb0068d19fcda115 Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Wed, 22 Apr 2026 19:05:00 +0100 Subject: [PATCH 01/16] Added H2 data files --- data/mydb.mv.db | Bin 0 -> 32768 bytes data/mydb.trace.db | 71 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 data/mydb.mv.db create mode 100644 data/mydb.trace.db diff --git a/data/mydb.mv.db b/data/mydb.mv.db new file mode 100644 index 0000000000000000000000000000000000000000..797a3e2899068be8666ba55e4efce998654a4f3e GIT binary patch literal 32768 zcmeHQ&2QVt6{qCHVUl$gD9|lXpa7#Jn;5GooFRu_r^vP(D=RCBB&W%tRfof2VniRV zEvIqN!ybxW3gobtUbZN(DA1ypo_g=8*i%vLbx{<>{uu>|J`O)j%X0h?Cr&ma8zhH% z9KQL@nB@Dt-_T1QF8jS9d*a#gy1n|Gdq~&yGJCu^c;cB1m06F|fd}h#PDecOkQ?~O z!aA{dIUKI{>Buw6Px<=B>Tn?$c);vOxvVr)wT&<@MokC`Bp?kqvGk72CdV28_T4 zBL*|DY9MAa>>$-3y6*=hP)(QH+zF9t`ouJCurV2CrpXSukQ&*k92K$h!4rn9@)=kxQki@2fcaw}w%FqPT?Ar5v`>M~t7LQC~c zI6ot<$}AmW6zD3Wm?3P0D)U1_2N%=;+bAH8qjKGdehihHAu~fBs+{^<$F`}4*wL9z zeb@-OkKkM(fC9bjTpF%FsyxP({?m=oaGh5IztY_7_3qQ&CSRZ<+Syv;(&o+JQy%M! z(X-0^SaQPy(IHW1TwbIMdTQ&+m@#x*Yxs+_%TlXTr{k;4LAr3f#u1#YGPgD2)%A6{ zmDc&29N!*!xdE)UKAacD2#bu39>Whcv`=1P^Tv^RH@4)%KEh z)pyMRnarXf&vo<=QEWLDhi6L8Lrg4-As#TtAS84gcrFeYGI78ycv_{F<8pdct1c|p zo0l|g=GVo)S8`o=b_fF-CLIU;;lyI*ZRtT%66 z!-UL^8!y6fU1-6+_UC3VYnNtznLv?xn1kVHzPCHoR!94By|bhttyRkv9c`}GxYNAV z?so2U1?E?@i!%#}19w~XWoVZ6Y3*Uohh%RT_I7beyVJ~l7k5+CL$e=iS7tU~_y9H& zI}`eTL7TtRYNJX{Xnc%2LXRpvEu?<@1qC3^WqyQz)c|Ah8w~6 z#s1+MA9U8~U;|5aSjv8Xq3v;2f_d1?4weoA{@${Sn}W^vnhTcr{9 zY+PB^vfY*`>yXt4_z9~teoxLClN7OY3H*CkX64#oj5QojI4mJN;=_`jo_tusZ3w4Q zexra3tl$=`f>SUGq~I6qBKC`zDN5l#KPXKps&ZEFP!-env#sDvA8xLd)nGc}o+>C_ z;dn*jl^?Iz?+Pi8q)X zZBpWJOX>imR^WJb5{Js194rScbpWqd+H$BaJCQ8t!N!Ty3hX6C7{{cz zv%yp2ZGtKb-=6*L9@!**h-}iIvvke=*`zpKgYwy=EMJporuWGuMTr^_L+wt~@LXIq zIkgo2A@h|dsU@!q2%OzQYgN| zL7+$Zq_|`t5JW>Ce-`JHihomz|GJ6h?JvlfLc8x00P~$@^AmsV*IV zK(YqeY_UUKhfX9wl^(tiM2Vy!fQBf(nE7jAObZ;uT3{{|zVD3|INVPQ97~p^78vx+ z$FBtriZ~+0zB&JSF|P&YnHD%a1bcHBMg+xiZk`db(wLW}^Vkp1h~)F(lNpiV%Z#@P z6W+!g%fOHGHc>V{rEN07a^fUOb;}7?vO7V)o3_b28K&9#U93$K@x#RMNCljfj?CJC z`nUMMSp7TorBwe4+Da}Y0ulj~@y@pM|WNdtJhNKU5$6$v4U zBNzq3$mH`LWiRCai!Y|XRmKR*FlH(RZE5JD@ZEoT0n;bHn_wRrlj-v11@UVtUhU-t zVbRcGH2&uFT0uFx{qlkwVVP2wOqbN9_vWd~j0A?uX#DR@$(X=tn_f*w;7IJ0@~faf zONCG3YG!8_Kp}vdpnuxMufmD**K+YPR1ibu305nT#Tk0`9*0*USZ{(X?tAeK^BwNPMu~t#Kq4R!kO)WwBm(a!0%`o8#^2k|j3^iXhY literal 0 HcmV?d00001 diff --git a/data/mydb.trace.db b/data/mydb.trace.db new file mode 100644 index 00000000..f5286f1b --- /dev/null +++ b/data/mydb.trace.db @@ -0,0 +1,71 @@ +2026-04-21 19:51:51.423293+01:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientException: The object is already closed [90007-224] +2026-04-22 05:55:04.822844+01:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientException: The object is already closed [90007-224] +2026-04-22 06:09:33.475810+01:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientException: The object is already closed [90007-224] +2026-04-22 06:16:11.292904+01:00 jdbc[16]: exception +org.h2.jdbc.JdbcSQLNonTransientException: The object is already closed [90007-224] +2026-04-22 12:24:23.617910+01:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientException: The object is already closed [90007-224] +2026-04-22 12:24:30.987650+01:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientException: The object is already closed [90007-224] +2026-04-22 12:24:33.627303+01:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLNonTransientException: The object is already closed [90007-224] +2026-04-22 16:38:46.730818Z jdbc[3]: exception +java.sql.SQLClientInfoException: Client info name 'ApplicationName' not supported. + at org.h2.jdbc.JdbcConnection.setClientInfo(JdbcConnection.java:1624) + at com.intellij.database.remote.jdbc.impl.RemoteConnectionImpl.setClientInfo(RemoteConnectionImpl.java:468) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360) + at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) + at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) + at java.base/java.security.AccessController.doPrivileged(AccessController.java:714) + at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) + at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:598) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:844) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:721) + at java.base/java.security.AccessController.doPrivileged(AccessController.java:400) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:720) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) +2026-04-22 16:38:53.145271Z jdbc[3]: exception +java.sql.SQLClientInfoException: Client info name 'ApplicationName' not supported. + at org.h2.jdbc.JdbcConnection.setClientInfo(JdbcConnection.java:1624) + at com.intellij.database.remote.jdbc.impl.RemoteConnectionImpl.setClientInfo(RemoteConnectionImpl.java:468) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360) + at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) + at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) + at java.base/java.security.AccessController.doPrivileged(AccessController.java:714) + at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) + at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:598) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:844) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:721) + at java.base/java.security.AccessController.doPrivileged(AccessController.java:400) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:720) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) +2026-04-22 16:39:21.684624Z jdbc[3]: exception +java.sql.SQLClientInfoException: Client info name 'ApplicationName' not supported. + at org.h2.jdbc.JdbcConnection.setClientInfo(JdbcConnection.java:1624) + at com.intellij.database.remote.jdbc.impl.RemoteConnectionImpl.setClientInfo(RemoteConnectionImpl.java:468) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360) + at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) + at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) + at java.base/java.security.AccessController.doPrivileged(AccessController.java:714) + at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) + at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:598) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:844) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:721) + at java.base/java.security.AccessController.doPrivileged(AccessController.java:400) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:720) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) From 80c7fb8a10c6a3d784213397f9a50c6eb5ae2d55 Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Wed, 22 Apr 2026 19:44:51 +0100 Subject: [PATCH 02/16] Added springboot starter test dependency --- pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pom.xml b/pom.xml index 8b415da1..b2aeda61 100644 --- a/pom.xml +++ b/pom.xml @@ -53,5 +53,13 @@ lombok true + + + + org.springframework.boot + spring-boot-starter-test + test + + From ce085ed9e91295aaf0f8fc051bb258fe8afd61de Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Thu, 23 Apr 2026 06:23:13 +0100 Subject: [PATCH 03/16] Added service layer unit tests --- .../service/UrlServiceImplTest.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/test/java/com/tpximpact/urlshortener/service/UrlServiceImplTest.java diff --git a/src/test/java/com/tpximpact/urlshortener/service/UrlServiceImplTest.java b/src/test/java/com/tpximpact/urlshortener/service/UrlServiceImplTest.java new file mode 100644 index 00000000..555efae4 --- /dev/null +++ b/src/test/java/com/tpximpact/urlshortener/service/UrlServiceImplTest.java @@ -0,0 +1,92 @@ +package com.tpximpact.urlshortener.service; + +import com.tpximpact.urlshortener.dto.UrlRequest; +import com.tpximpact.urlshortener.entity.Url; +import com.tpximpact.urlshortener.exception.BadRequestException; +import com.tpximpact.urlshortener.exception.NotFoundException; +import com.tpximpact.urlshortener.repository.UrlRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(org.mockito.junit.jupiter.MockitoExtension.class) +class UrlServiceImplTest { + + @Mock + private UrlRepository repository; + + @InjectMocks + private UrlServiceImpl service; + + private UrlRequest request; + private Url url; + + @BeforeEach + public void setUp() { + request = new UrlRequest("https://google.com", "alias1"); + + url = Url.builder() + .alias("alias1") + .fullUrl("https://google.com") + .build(); + } + + @Test + void shouldCreateShortUrl_withCustomAlias() { + + when(repository.existsByAlias("alias1")).thenReturn(false); + + var response = service.shorten(request); + + assertThat(response.shortUrl()).contains("alias1"); + verify(repository).existsByAlias("alias1"); + } + + @Test + void shouldThrowException_whenAliasAlreadyExists() { + + when(repository.existsByAlias("alias1")).thenReturn(true); + + assertThatThrownBy(() -> service.shorten(request)) + .isInstanceOf(BadRequestException.class) + .hasMessageContaining("Invalid input or alias already taken"); + } + + @Test + void shouldReturnFullUrl_whenAliasExists() { + + when(repository.findByAlias("alias1")).thenReturn(Optional.of(url)); + + var result = service.getFullUrl("alias1"); + + assertThat(result).isEqualTo("https://google.com"); + } + + @Test + void shouldThrowNotFound_whenAliasMissing() { + when(repository.findByAlias("abc")).thenReturn(Optional.empty()); + + assertThatThrownBy(() -> service.getFullUrl("abc")) + .isInstanceOf(NotFoundException.class); + } + + @Test + void shouldDelete_whenAliasExists() { + Url url = Url.builder().alias("abc").build(); + + when(repository.findByAlias("abc")).thenReturn(Optional.of(url)); + + service.delete("abc"); + + verify(repository).delete(url); + } +} \ No newline at end of file From f24f104ffb013fe085b5be7bbdc5ff60eb0d08d0 Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Fri, 24 Apr 2026 05:56:09 +0100 Subject: [PATCH 04/16] Updated H2 Db as part of testing --- data/mydb.mv.db | Bin 32768 -> 40960 bytes data/mydb.trace.db | 2 ++ 2 files changed, 2 insertions(+) diff --git a/data/mydb.mv.db b/data/mydb.mv.db index 797a3e2899068be8666ba55e4efce998654a4f3e..462f5d124a02f370daf91b2d99cf4502d9dd4c8f 100644 GIT binary patch literal 40960 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 EAJIp}aR2}S delta 2336 zcmbtW|7#mn0Dte&r1@gfF>KvhHPAr54uF)y8(>4-@+C?wu`7FIjUb zb%^cnLS=nFs4x-6Kv8s*&>#F^I1omMpku$u7-Q@Y*uWnJ_1#@^xz^4qCLwq4?s56N z&$pNLTg>`8!=2ScPA^xCMQzAG&MaKUn!xisXUx~_MNKvY&M0GKYr>WMiRbCaDr3i( z$IDt#M5cwrznrM)2r@wCn zFV_|-wkFfrHePk;G^b){f~;VI*t5wb0LiPF4Zxfv+j9bWGPg_?(3LpmCHE~gUev#b zgr7f6elm|YCe2sf!L`Peb+m(?lo}rvqA=R=WvT=l4fY4v`N7y*Qd9$;bIIc*(mRKQ{2%-rFa0qmvV( zGr3a$FdK=74D10>y1X-D%=^~;gW+A1$ld83@?9y*=qCB4ls%%G-8NdnTBVBZ*=1zc zkl|1=YK^C*aX29AjA#G=AH9%^fH+8a5}uKDJvcMTMX|8w)@V;#ID^u!5&O z5ky~vVa$6M&%27yb59V&EmtazCWzRej^Slf9Tquff#Q>}Y|4tk)$Mu>o1@O#foLYT zvK9<svI@VQV{HJN(E#q7chz4*jp&u@*C8a^`IQ_lthgp8M6mPW{xzRe`ncT_T2h1rq zSB)ogDfrA#^~HiLWnd(;15+^onMgF&NpAALCFoLS<5!vIV&qrhT$YaDG<|f<{PQBSR0GL8!du|*yQu@WX z*RyWD=9rE2Hr&&Drr&#bZ|_-t?^*xYdnO}d>Z1FpO(xuXIOsjgbrJOS68r^)^-?{( z$W!MCF`OP~lFQEZf-9BeCYqLph22ayNBc{ap+RN-@Pit;MuXbXMT2@gU^C#KUI~J# z>qE#yir7qQhnG~k$+`lx+Rpcv+T>s2$;&HY{so`^qQ}2tC=w6~BDl`T>Y{=bt-CCJtb-AxHxPqiXL zpZ0EjS7hjw8})up^>ql^`v4u-^a$ Date: Fri, 24 Apr 2026 05:59:47 +0100 Subject: [PATCH 05/16] Upgraded parent starter dependency to 4.0.1 from 3.2.0, 3.0.2 is in the end of life phase(deprecated).Good to upgrade before tests, save tests fixing time. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b2aeda61..233ff834 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.0 + 4.0.1 From ff2cd29cdfe9d29737f9d4265d5150bfc5b92e27 Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Fri, 24 Apr 2026 06:38:02 +0100 Subject: [PATCH 06/16] Upgraded parent starter dependency to 4.0.5 from 4.0.1 to remove vulnerabilities warnings. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 233ff834..a2daade9 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ org.springframework.boot spring-boot-starter-parent - 4.0.1 + 4.0.5 From 0c396fd11e3a2ca58476ada92ab78d5a508cd3d1 Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Fri, 24 Apr 2026 23:39:32 +0100 Subject: [PATCH 07/16] Moved back to 3.5.0 to avoid modularised tech saperation package issues --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a2daade9..db8dc06e 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ org.springframework.boot spring-boot-starter-parent - 4.0.5 + 3.5.0 From 0a1f68d94bf127b495e13522c418a4e739fc574e Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Fri, 24 Apr 2026 23:40:12 +0100 Subject: [PATCH 08/16] Added web integration(E2E) tests --- .../controller/UrlControllerWIT.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/test/java/com/tpximpact/urlshortener/controller/UrlControllerWIT.java diff --git a/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerWIT.java b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerWIT.java new file mode 100644 index 00000000..f2973462 --- /dev/null +++ b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerWIT.java @@ -0,0 +1,90 @@ +package com.tpximpact.urlshortener.controller; + +import com.tpximpact.urlshortener.dto.UrlListResponse; +import com.tpximpact.urlshortener.dto.UrlRequest; +import com.tpximpact.urlshortener.dto.UrlResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +class UrlControllerWIT { + @Autowired + private TestRestTemplate restTemplate; + + + @Test + @DisplayName("POST /shorten - Should create short URL") + void shouldCreateShortUrl() { + // Given + UrlRequest request = new UrlRequest("https://tpximpact.com", "tpx"); + + // When + ResponseEntity response = restTemplate.postForEntity( + "/shorten", + request, + UrlResponse.class + ); + + // Then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().shortUrl()).contains("/tpx"); + } + + @Test + @DisplayName("GET /{alias} - Should return 302 Redirect") + void shouldRedirect() { + // First, ensure the URL exists (Seed the data) + restTemplate.postForEntity("/shorten", new UrlRequest("https://google.com", "goog"), UrlResponse.class); + + // When - We use getForEntity + ResponseEntity response = restTemplate.getForEntity("/{alias}", Void.class, "goog"); + + // Then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } + + @Test + @DisplayName("GET /urls - Should return list using TestRestTemplate") + void getAllRestTemplate() { + ResponseEntity response = restTemplate.getForEntity( + "/urls", + UrlListResponse[].class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + + // Convert array to list for easier assertions + List urls = Arrays.asList(response.getBody()); + assertThat(urls).isNotEmpty(); + assertThat(urls.get(0).alias()).isEqualTo("goog"); + + + } + + @Test + @DisplayName("DELETE /{alias} - Should remove entry") + void shouldDelete() { + // When + restTemplate.delete("/{alias}", "tpx"); + + // Then - Verify 404 after deletion + ResponseEntity response = restTemplate.getForEntity("/{alias}", Void.class, "tpx"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + +} From d631bdf7c761b4d14b420da6a49be8fb237b6dde Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Fri, 24 Apr 2026 23:43:33 +0100 Subject: [PATCH 09/16] Added controller unit tests --- .../controller/UrlControllerTest.java | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/test/java/com/tpximpact/urlshortener/controller/UrlControllerTest.java diff --git a/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerTest.java b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerTest.java new file mode 100644 index 00000000..136b7555 --- /dev/null +++ b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerTest.java @@ -0,0 +1,126 @@ +package com.tpximpact.urlshortener.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tpximpact.urlshortener.dto.UrlListResponse; +import com.tpximpact.urlshortener.dto.UrlRequest; +import com.tpximpact.urlshortener.dto.UrlResponse; +import com.tpximpact.urlshortener.exception.NotFoundException; +import com.tpximpact.urlshortener.service.UrlService; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.bean.override.mockito.MockitoBean; // SB 4.0 standard +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(UrlController.class) +class UrlControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockitoBean + private UrlService urlService; + + @Test + @DisplayName("POST /shorten - Success") + void shortenUrl_Returns201() throws Exception { + // Given + UrlRequest request = new UrlRequest("https://example.com", "my-alias"); + UrlResponse response = new UrlResponse("http://localhost:8080/my-alias"); + + when(urlService.shorten(any(UrlRequest.class))).thenReturn(response); + + // When & Then + mockMvc.perform(post("/shorten") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.shortUrl").value("http://localhost:8080/my-alias")); + + verify(urlService, times(1)).shorten(any(UrlRequest.class)); + } + + @Test + @DisplayName("GET /{alias} - Redirects to full URL") + void redirect_Returns302() throws Exception { + // Given + String alias = "tpx"; + String fullUrl = "https://tpximpact.com"; + when(urlService.getFullUrl(alias)).thenReturn(fullUrl); + + // When & Then + mockMvc.perform(get("/{alias}", alias)) + .andExpect(status().isFound()) + .andExpect(header().string("Location", fullUrl)) + .andExpect(content().string("")); // Asserting empty body as requested + + verify(urlService).getFullUrl(alias); + } + + @Test + @DisplayName("GET /{alias} - Redirects returns 404 if alias not exist") + void redirect_Returns404_If_Alias_Not_Exist() throws Exception { + // Given + String aliasNotExist = "notExist"; + String fullUrl = "https://tpximpact.com"; + when(urlService.getFullUrl(aliasNotExist)).thenThrow(NotFoundException.class); + + // When & Then + mockMvc.perform(get("/{alias}", aliasNotExist)) + .andExpect(status().isNotFound()); + + verify(urlService).getFullUrl(aliasNotExist); + } + + @Test + @DisplayName("GET /urls - Returns list of mappings") + void getAll_Returns200() throws Exception { + // Given + List mockList = List.of( + new UrlListResponse("alias1", "https://site1.com", "http://short/1"), + new UrlListResponse("alias2", "https://site2.com", "http://short/2") + ); + when(urlService.getAll()).thenReturn(mockList); + + // When & Then + mockMvc.perform(get("/urls")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.length()").value(2)) + .andExpect(jsonPath("$[0].alias").value("alias1")); + } + + @Test + @DisplayName("DELETE /{alias} - Success") + void delete_Returns204() throws Exception { + // When & Then + mockMvc.perform(delete("/{alias}", "old-alias")) + .andExpect(status().isNoContent()); + + verify(urlService).delete("old-alias"); + } + + @Test + @DisplayName("POST /shorten - Fails on invalid input") + void shortenUrl_BlankUrl_Returns400() throws Exception { + UrlRequest invalidRequest = new UrlRequest("", "alias"); + + mockMvc.perform(post("/shorten") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(invalidRequest))) + .andExpect(status().isBadRequest()); + + verifyNoInteractions(urlService); + } +} \ No newline at end of file From 795d1bb5218d70dbbdbd1404f431d8b9ce7e3f50 Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Fri, 24 Apr 2026 23:46:59 +0100 Subject: [PATCH 10/16] Added controller integration Mockmvc tests to verify API flow, especially redirection endpoint testing. --- .../UrlControllerIntegrationTest.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java diff --git a/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java new file mode 100644 index 00000000..ab5c0ea0 --- /dev/null +++ b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java @@ -0,0 +1,73 @@ +package com.tpximpact.urlshortener.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tpximpact.urlshortener.dto.UrlRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +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.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@SpringBootTest +@AutoConfigureMockMvc +@Transactional // Rolls back database changes after each test to ensure a clean state +class UrlControllerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Test + @DisplayName("Full integration flow: Create, Redirect, List, and Delete") + void testUrlLifecycle() throws Exception { + String longUrl = "https://www.tpximpact.com"; + String alias = "tpx"; + UrlRequest request = new UrlRequest(longUrl, alias); + + // 1. POST /shorten - Create a new mapping + mockMvc.perform(post("/shorten") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.shortUrl").exists()); + + // 2. GET /{alias} - Test redirection logic + mockMvc.perform(get("/{alias}", alias)) + .andExpect(status().isFound()) // 302 + .andExpect(header().string("Location", longUrl)) + .andExpect(content().string("")); + + // 3. GET /urls - Verify the alias appears in the list + mockMvc.perform(get("/urls")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray()) + .andExpect(jsonPath("$[?(@.alias == '" + alias + "')]").exists()); + + // 4. DELETE /{alias} - Remove the mapping + mockMvc.perform(delete("/{alias}", alias)) + .andExpect(status().isNoContent()); + + // 5. GET /{alias} - Verify it no longer exists (assuming service throws 404) + mockMvc.perform(get("/{alias}", alias)) + .andExpect(status().isNotFound()); + } + + @Test + @DisplayName("POST /shorten - Should return 400 when fullUrl is blank") + void shouldReturn400ForInvalidInput() throws Exception { + UrlRequest invalidRequest = new UrlRequest("", "short"); + + mockMvc.perform(post("/shorten") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(invalidRequest))) + .andExpect(status().isBadRequest()); + } +} \ No newline at end of file From b6b0f670ed9f05d89da730063898864fe6609e1d Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Fri, 24 Apr 2026 23:49:18 +0100 Subject: [PATCH 11/16] Removed unused variable --- .../com/tpximpact/urlshortener/controller/UrlControllerTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerTest.java b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerTest.java index 136b7555..41a2cffb 100644 --- a/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerTest.java +++ b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerTest.java @@ -74,7 +74,6 @@ void redirect_Returns302() throws Exception { void redirect_Returns404_If_Alias_Not_Exist() throws Exception { // Given String aliasNotExist = "notExist"; - String fullUrl = "https://tpximpact.com"; when(urlService.getFullUrl(aliasNotExist)).thenThrow(NotFoundException.class); // When & Then From 3823260d39a33f1871ba099fc0a21df8fee9126a Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Fri, 24 Apr 2026 23:49:57 +0100 Subject: [PATCH 12/16] Rename DB and added more capabilities --- src/main/resources/application-dev.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 819ffce0..4ea6c307 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -1,6 +1,6 @@ spring: datasource: - url: jdbc:h2:file:./data/mydb + url: jdbc:h2:file:./data/url-shorten-db;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE driver-class-name: org.h2.Driver username: sa password: From dd903e8bdb0d22c517501413c762a5cfe6474870 Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Sun, 26 Apr 2026 15:38:27 +0100 Subject: [PATCH 13/16] We don't need @Transactional, data jpa handles that. --- .../urlshortener/controller/UrlControllerIntegrationTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java index ab5c0ea0..389991ca 100644 --- a/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java +++ b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java @@ -16,7 +16,6 @@ @SpringBootTest @AutoConfigureMockMvc -@Transactional // Rolls back database changes after each test to ensure a clean state class UrlControllerIntegrationTest { @Autowired From 518d3caeb06545f473dd2bb7fcbc9356d47452bd Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Sun, 26 Apr 2026 15:38:55 +0100 Subject: [PATCH 14/16] Remove unused import --- .../controller/UrlControllerIntegrationTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java index 389991ca..a2d7cbbc 100644 --- a/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java +++ b/src/test/java/com/tpximpact/urlshortener/controller/UrlControllerIntegrationTest.java @@ -9,10 +9,14 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.transaction.annotation.Transactional; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc From 9bbc0eee5d51ff7ece2bbf5148763a47ef6e7015 Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Sun, 26 Apr 2026 15:39:32 +0100 Subject: [PATCH 15/16] Commit DB data --- data/mydb.mv.db | Bin 40960 -> 32768 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/mydb.mv.db b/data/mydb.mv.db index 462f5d124a02f370daf91b2d99cf4502d9dd4c8f..98a638489001b4dfa48009197c1f498845b8f35f 100644 GIT binary patch literal 32768 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 EAJIp}aR2}S From f0b4babba347cc3ee80adea6f80a537e8cdc724b Mon Sep 17 00:00:00 2001 From: Upendra Kumbham Date: Sun, 26 Apr 2026 15:40:17 +0100 Subject: [PATCH 16/16] Added test properties file --- src/test/resources/application-test.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/test/resources/application-test.yaml diff --git a/src/test/resources/application-test.yaml b/src/test/resources/application-test.yaml new file mode 100644 index 00000000..5421926e --- /dev/null +++ b/src/test/resources/application-test.yaml @@ -0,0 +1,10 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + driverClassName: org.h2.Driver + jpa: + hibernate: + ddl-auto: create-drop + h2: + console: + enabled: true \ No newline at end of file