Skip to content

Commit 46b555b

Browse files
committed
Refactor DatasetService to use MultipartFile for file upload handling
- Replaced `Resource` with `MultipartFile` in `uploadTwingraph` and `twingraphBatchUpdate` for consistency and flexibility. - Updated related service methods, unit tests, and integration tests to support the change. - Added validations for filenames to enhance security. - Adjusted import paths for `RediSearchIndexer` in relevant modules.
1 parent 0b86274 commit 46b555b

File tree

4 files changed

+130
-93
lines changed

4 files changed

+130
-93
lines changed

dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceIntegrationTest.kt

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,14 @@ import com.cosmotech.workspace.domain.WorkspaceAccessControl
5454
import com.cosmotech.workspace.domain.WorkspaceSecurity
5555
import com.cosmotech.workspace.domain.WorkspaceSolution
5656
import com.ninjasquad.springmockk.SpykBean
57-
import com.redis.om.spring.RediSearchIndexer
57+
import com.redis.om.spring.indexing.RediSearchIndexer
5858
import com.redis.testcontainers.RedisStackContainer
5959
import io.mockk.clearAllMocks
6060
import io.mockk.every
6161
import io.mockk.impl.annotations.MockK
6262
import io.mockk.junit5.MockKExtension
6363
import io.mockk.mockk
6464
import io.mockk.mockkStatic
65-
import java.io.File
6665
import java.time.Instant
6766
import java.util.*
6867
import kotlin.test.Test
@@ -79,11 +78,11 @@ import org.junit.runner.RunWith
7978
import org.slf4j.LoggerFactory
8079
import org.springframework.beans.factory.annotation.Autowired
8180
import org.springframework.boot.test.context.SpringBootTest
82-
import org.springframework.core.io.ByteArrayResource
8381
import org.springframework.test.context.ActiveProfiles
8482
import org.springframework.test.context.junit.jupiter.SpringExtension
8583
import org.springframework.test.context.junit4.SpringRunner
8684
import org.springframework.test.util.ReflectionTestUtils
85+
import org.springframework.web.multipart.MultipartFile
8786
import redis.clients.jedis.HostAndPort
8887
import redis.clients.jedis.Protocol
8988
import redis.clients.jedis.UnifiedJedis
@@ -503,6 +502,7 @@ class DatasetServiceIntegrationTest : CsmRedisTestBase() {
503502
assertEquals(1, datasetList.size)
504503
assertEquals(datasetNotReachableByCurrentUserBecausePartOfAnotherOrganization, datasetList[0])
505504
}
505+
506506
@Test
507507
fun `test find All Datasets with wrong pagination params`() {
508508
organizationSaved = organizationApiService.registerOrganization(organization)
@@ -529,8 +529,12 @@ class DatasetServiceIntegrationTest : CsmRedisTestBase() {
529529
logger.info("Create a Graph with a ZIP Entry")
530530
logger.info(
531531
"loading nodes: Double=2, Single=1, Users=9 & relationships: Double=2, Single=1, Follows=2")
532-
val file = this::class.java.getResource("/integrationTest.zip")?.file
533-
val resource = ByteArrayResource(File(file!!).readBytes())
532+
533+
val file = mockk<MultipartFile>(relaxed = true)
534+
val inputStream = this::class.java.getResourceAsStream("/integrationTest.zip")
535+
every { file.originalFilename } returns "integrationTest.zip"
536+
every { file.inputStream } returns inputStream!!
537+
534538
organizationSaved = organizationApiService.registerOrganization(organization)
535539
dataset = makeDatasetWithRole()
536540
datasetSaved = datasetApiService.createDataset(organizationSaved.id!!, dataset)
@@ -540,7 +544,7 @@ class DatasetServiceIntegrationTest : CsmRedisTestBase() {
540544
dataset.copy(sourceType = DatasetSourceType.File))
541545

542546
val fileUploadValidation =
543-
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, resource)
547+
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, file)
544548
assertEquals(
545549
FileUploadValidation(
546550
mutableListOf(
@@ -745,10 +749,13 @@ class DatasetServiceIntegrationTest : CsmRedisTestBase() {
745749
organizationSaved = organizationApiService.registerOrganization(organization)
746750
dataset.apply { sourceType = DatasetSourceType.File }
747751
datasetSaved = datasetApiService.createDataset(organizationSaved.id!!, dataset)
748-
val file = this::class.java.getResource("/integrationTest.zip")?.file
749-
val resource = ByteArrayResource(File(file!!).readBytes())
750752

751-
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, resource)
753+
val file = mockk<MultipartFile>(relaxed = true)
754+
val inputStream = this::class.java.getResourceAsStream("/integrationTest.zip")
755+
every { file.originalFilename } returns "integrationTest.zip"
756+
every { file.inputStream } returns inputStream!!
757+
758+
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, file)
752759

753760
var datasetStatus: String
754761
do {
@@ -770,10 +777,11 @@ class DatasetServiceIntegrationTest : CsmRedisTestBase() {
770777
organizationSaved = organizationApiService.registerOrganization(organization)
771778
dataset.apply { sourceType = DatasetSourceType.File }
772779
datasetSaved = datasetApiService.createDataset(organizationSaved.id!!, dataset)
773-
val file = this::class.java.getResource("/brokenGraph.zip")?.file
774-
val resource = ByteArrayResource(File(file!!).readBytes())
775-
776-
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, resource)
780+
val file = mockk<MultipartFile>(relaxed = true)
781+
val inputStream = this::class.java.getResourceAsStream("/brokenGraph.zip")
782+
every { file.originalFilename } returns "brokenGraph.zip"
783+
every { file.inputStream } returns inputStream!!
784+
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, file)
777785

778786
var datasetStatus: String
779787
do {
@@ -830,11 +838,11 @@ class DatasetServiceIntegrationTest : CsmRedisTestBase() {
830838
organizationSaved = organizationApiService.registerOrganization(organization)
831839
dataset.apply { sourceType = DatasetSourceType.File }
832840
datasetSaved = datasetApiService.createDataset(organizationSaved.id!!, dataset)
833-
834-
val fileName = this::class.java.getResource("/integrationTest.zip")?.file
835-
val file = File(fileName!!)
836-
val resource = ByteArrayResource(file.readBytes())
837-
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, resource)
841+
val file = mockk<MultipartFile>(relaxed = true)
842+
var inputStream = this::class.java.getResourceAsStream("/integrationTest.zip")
843+
every { file.originalFilename } returns "integrationTest.zip"
844+
every { file.inputStream } returns inputStream!!
845+
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, file)
838846
do {
839847
Thread.sleep(50L)
840848
} while (datasetApiService.getDatasetTwingraphStatus(
@@ -848,8 +856,11 @@ class DatasetServiceIntegrationTest : CsmRedisTestBase() {
848856
val queryResult =
849857
datasetApiService.twingraphQuery(
850858
organizationSaved.id!!, datasetSaved.id!!, DatasetTwinGraphQuery("MATCH (n) RETURN n"))
851-
852-
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, resource)
859+
val reuploadFile = mockk<MultipartFile>(relaxed = true)
860+
inputStream = this::class.java.getResourceAsStream("/integrationTest.zip")
861+
every { reuploadFile.originalFilename } returns "integrationTest.zip"
862+
every { reuploadFile.inputStream } returns inputStream!!
863+
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, reuploadFile)
853864
do {
854865
Thread.sleep(50L)
855866
} while (datasetApiService.getDatasetTwingraphStatus(
@@ -907,10 +918,11 @@ class DatasetServiceIntegrationTest : CsmRedisTestBase() {
907918
assertEquals(IngestionStatusEnum.NONE.value, datasetStatus)
908919

909920
every { datasetApiService.query(any(), any()) } returns mockk()
910-
val fileName = this::class.java.getResource("/integrationTest.zip")?.file
911-
val file = File(fileName!!)
912-
val resource = ByteArrayResource(file.readBytes())
913-
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, resource)
921+
val file = mockk<MultipartFile>(relaxed = true)
922+
val inputStream = this::class.java.getResourceAsStream("/integrationTest.zip")
923+
every { file.originalFilename } returns "integrationTest.zip"
924+
every { file.inputStream } returns inputStream!!
925+
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, file)
914926
do {
915927
Thread.sleep(50L)
916928
datasetStatus =
@@ -1134,6 +1146,7 @@ class DatasetServiceIntegrationTest : CsmRedisTestBase() {
11341146
OrganizationAccessControl(id = CONNECTED_ADMIN_USER, role = ROLE_ADMIN),
11351147
OrganizationAccessControl(id = userName, role = role))))
11361148
}
1149+
11371150
fun makeDataset(
11381151
organizationId: String = organizationSaved.id!!,
11391152
parentId: String = "",

dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceRBACTest.kt

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ import com.cosmotech.organization.domain.Organization
4747
import com.cosmotech.organization.domain.OrganizationAccessControl
4848
import com.cosmotech.organization.domain.OrganizationSecurity
4949
import com.ninjasquad.springmockk.SpykBean
50-
import com.redis.om.spring.RediSearchIndexer
50+
import com.redis.om.spring.indexing.RediSearchIndexer
5151
import com.redis.testcontainers.RedisStackContainer
5252
import io.mockk.clearAllMocks
5353
import io.mockk.every
5454
import io.mockk.impl.annotations.MockK
5555
import io.mockk.junit5.MockKExtension
5656
import io.mockk.mockk
5757
import io.mockk.mockkStatic
58-
import java.io.File
58+
import java.io.InputStream
5959
import java.util.*
6060
import kotlin.test.assertEquals
6161
import kotlinx.coroutines.test.advanceUntilIdle
@@ -72,13 +72,13 @@ import org.junit.runner.RunWith
7272
import org.slf4j.LoggerFactory
7373
import org.springframework.beans.factory.annotation.Autowired
7474
import org.springframework.boot.test.context.SpringBootTest
75-
import org.springframework.core.io.ByteArrayResource
7675
import org.springframework.test.context.ActiveProfiles
7776
import org.springframework.test.context.junit.jupiter.SpringExtension
7877
import org.springframework.test.context.junit4.SpringRunner
7978
import org.springframework.test.util.ReflectionTestUtils
8079
import org.springframework.web.context.request.RequestContextHolder
8180
import org.springframework.web.context.request.ServletRequestAttributes
81+
import org.springframework.web.multipart.MultipartFile
8282
import redis.clients.jedis.HostAndPort
8383
import redis.clients.jedis.UnifiedJedis
8484

@@ -105,7 +105,6 @@ class DatasetServiceRBACTest : CsmRedisTestBase() {
105105
lateinit var dataset: Dataset
106106
lateinit var dataset2: Dataset
107107
lateinit var datasetSaved: Dataset
108-
lateinit var retrievedDataset1: Dataset
109108

110109
lateinit var jedis: UnifiedJedis
111110
lateinit var organization: Organization
@@ -243,26 +242,29 @@ class DatasetServiceRBACTest : CsmRedisTestBase() {
243242
materializeTwingraph()
244243

245244
val datasetTwinGraphQuery = DatasetTwinGraphQuery("MATCH (n) RETURN n")
246-
val resource = ByteArrayResource("".toByteArray())
247-
every { resourceScanner.scanMimeTypes(any(), any()) } returns Unit
245+
246+
every {
247+
resourceScanner.scanMimeTypes(any(), any(), listOf("text/csv", "text/plain"))
248+
} returns Unit
248249
every { getCurrentAccountIdentifier(any()) } returns TEST_USER_MAIL
249250

251+
val file = mockk<MultipartFile>(relaxed = true)
252+
val inputStream = this::class.java.getResourceAsStream("/integrationTest.zip")
253+
every { file.originalFilename } returns "integrationTest.zip"
254+
every { file.inputStream } returns inputStream!!
250255
if (shouldThrow) {
251256
val exception =
252257
assertThrows<CsmAccessForbiddenException> {
253258
datasetApiService.twingraphBatchUpdate(
254-
organizationSaved.id!!,
255-
datasetSaved.id!!,
256-
datasetTwinGraphQuery,
257-
resource)
259+
organizationSaved.id!!, datasetSaved.id!!, datasetTwinGraphQuery, file)
258260
}
259261
assertEquals(
260262
"RBAC ${organizationSaved.id!!} - User does not have permission $PERMISSION_READ",
261263
exception.message)
262264
} else {
263265
assertDoesNotThrow {
264266
datasetApiService.twingraphBatchUpdate(
265-
organizationSaved.id!!, datasetSaved.id!!, datasetTwinGraphQuery, resource)
267+
organizationSaved.id!!, datasetSaved.id!!, datasetTwinGraphQuery, file)
266268
}
267269
}
268270
}
@@ -288,18 +290,18 @@ class DatasetServiceRBACTest : CsmRedisTestBase() {
288290
materializeTwingraph()
289291

290292
val datasetTwinGraphQuery = DatasetTwinGraphQuery("MATCH (n) RETURN n")
291-
val resource = ByteArrayResource("".toByteArray())
292-
every { resourceScanner.scanMimeTypes(any(), any()) } returns Unit
293+
every {
294+
resourceScanner.scanMimeTypes(any(), any(), listOf("text/csv", "text/plain"))
295+
} returns Unit
293296
every { getCurrentAccountIdentifier(any()) } returns TEST_USER_MAIL
294-
297+
val file = mockk<MultipartFile>(relaxed = true)
298+
every { file.originalFilename } returns "nullEmptyStream.zip"
299+
every { file.inputStream } returns InputStream.nullInputStream()
295300
if (shouldThrow) {
296301
val exception =
297302
assertThrows<CsmAccessForbiddenException> {
298303
datasetApiService.twingraphBatchUpdate(
299-
organizationSaved.id!!,
300-
datasetSaved.id!!,
301-
datasetTwinGraphQuery,
302-
resource)
304+
organizationSaved.id!!, datasetSaved.id!!, datasetTwinGraphQuery, file)
303305
}
304306
if (role == ROLE_NONE) {
305307
assertEquals(
@@ -313,7 +315,7 @@ class DatasetServiceRBACTest : CsmRedisTestBase() {
313315
} else {
314316
assertDoesNotThrow {
315317
datasetApiService.twingraphBatchUpdate(
316-
organizationSaved.id!!, datasetSaved.id!!, datasetTwinGraphQuery, resource)
318+
organizationSaved.id!!, datasetSaved.id!!, datasetTwinGraphQuery, file)
317319
}
318320
}
319321
}
@@ -1663,25 +1665,28 @@ class DatasetServiceRBACTest : CsmRedisTestBase() {
16631665
val dataset =
16641666
makeDatasetWithRole(role = ROLE_ADMIN, sourceType = DatasetSourceType.File)
16651667
datasetSaved = datasetApiService.createDataset(organizationSaved.id!!, dataset)
1666-
val fileName = this::class.java.getResource("/integrationTest.zip")?.file
1667-
val file = File(fileName!!)
1668-
val resource = ByteArrayResource(file.readBytes())
1669-
1668+
every {
1669+
resourceScanner.scanMimeTypes(any(), any(), listOf("text/csv", "text/plain"))
1670+
} returns Unit
16701671
every { getCurrentAccountIdentifier(any()) } returns TEST_USER_MAIL
16711672

1673+
val file = mockk<MultipartFile>(relaxed = true)
1674+
val inputStream = this::class.java.getResourceAsStream("/integrationTest.zip")
1675+
every { file.originalFilename } returns "integrationTest.zip"
1676+
every { file.inputStream } returns inputStream!!
1677+
16721678
if (shouldThrow) {
16731679
val exception =
16741680
assertThrows<CsmAccessForbiddenException> {
16751681
datasetApiService.uploadTwingraph(
1676-
organizationSaved.id!!, datasetSaved.id!!, resource)
1682+
organizationSaved.id!!, datasetSaved.id!!, file)
16771683
}
16781684
assertEquals(
16791685
"RBAC ${organizationSaved.id!!} - User does not have permission $PERMISSION_READ",
16801686
exception.message)
16811687
} else {
16821688
assertDoesNotThrow {
1683-
datasetApiService.uploadTwingraph(
1684-
organizationSaved.id!!, datasetSaved.id!!, resource)
1689+
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, file)
16851690
}
16861691
}
16871692
}
@@ -1704,17 +1709,23 @@ class DatasetServiceRBACTest : CsmRedisTestBase() {
17041709
organizationSaved = organizationApiService.registerOrganization(organization)
17051710
val dataset = makeDatasetWithRole(role = role, sourceType = DatasetSourceType.File)
17061711
datasetSaved = datasetApiService.createDataset(organizationSaved.id!!, dataset)
1707-
val fileName = this::class.java.getResource("/integrationTest.zip")?.file
1708-
val file = File(fileName!!)
1709-
val resource = ByteArrayResource(file.readBytes())
1712+
every {
1713+
resourceScanner.scanMimeTypes(any(), any(), listOf("text/csv", "text/plain"))
1714+
} returns Unit
1715+
every { getCurrentAccountIdentifier(any()) } returns TEST_USER_MAIL
1716+
1717+
val file = mockk<MultipartFile>(relaxed = true)
1718+
val inputStream = this::class.java.getResourceAsStream("/integrationTest.zip")
1719+
every { file.originalFilename } returns "integrationTest.zip"
1720+
every { file.inputStream } returns inputStream!!
17101721

17111722
every { getCurrentAccountIdentifier(any()) } returns TEST_USER_MAIL
17121723

17131724
if (shouldThrow) {
17141725
val exception =
17151726
assertThrows<CsmAccessForbiddenException> {
17161727
datasetApiService.uploadTwingraph(
1717-
organizationSaved.id!!, datasetSaved.id!!, resource)
1728+
organizationSaved.id!!, datasetSaved.id!!, file)
17181729
}
17191730
if (role == ROLE_NONE) {
17201731
assertEquals(
@@ -1727,8 +1738,7 @@ class DatasetServiceRBACTest : CsmRedisTestBase() {
17271738
}
17281739
} else {
17291740
assertDoesNotThrow {
1730-
datasetApiService.uploadTwingraph(
1731-
organizationSaved.id!!, datasetSaved.id!!, resource)
1741+
datasetApiService.uploadTwingraph(organizationSaved.id!!, datasetSaved.id!!, file)
17321742
}
17331743
}
17341744
}
@@ -2312,6 +2322,7 @@ class DatasetServiceRBACTest : CsmRedisTestBase() {
23122322
ioTypes = listOf(),
23132323
id = "c-AbCdEf123")
23142324
}
2325+
23152326
fun makeDataset(
23162327
id: String,
23172328
name: String,

0 commit comments

Comments
 (0)