@@ -2,9 +2,12 @@ package org.radarbase.output
2
2
3
3
import io.minio.*
4
4
import io.minio.ObjectWriteArgs.MAX_PART_SIZE
5
+ import kotlinx.coroutines.*
6
+ import kotlinx.coroutines.test.runTest
5
7
import org.junit.jupiter.api.Assertions.assertEquals
6
8
import org.junit.jupiter.api.Test
7
9
import org.radarbase.output.config.*
10
+ import org.radarbase.output.util.SuspendedCloseable.Companion.useSuspended
8
11
import org.radarbase.output.util.Timer
9
12
import org.radarbase.output.util.bucketBuild
10
13
import org.radarbase.output.util.objectBuild
@@ -13,7 +16,7 @@ import java.nio.file.Paths
13
16
14
17
class RestructureS3IntegrationTest {
15
18
@Test
16
- fun integration () {
19
+ fun integration () = runTest {
17
20
Timer .isEnabled = true
18
21
val sourceConfig = S3Config (
19
22
endpoint = " http://localhost:9000" ,
@@ -38,77 +41,106 @@ class RestructureS3IntegrationTest {
38
41
}
39
42
40
43
val resourceFiles = listOf (
41
- " application_server_status/partition=1/application_server_status+1+0000000018+0000000020.avro" ,
42
- " application_server_status/partition=1/application_server_status+1+0000000021.avro" ,
43
- " android_phone_acceleration/partition=0/android_phone_acceleration+0+0003018784.avro"
44
+ " application_server_status/partition=1/application_server_status+1+0000000018+0000000020.avro" ,
45
+ " application_server_status/partition=1/application_server_status+1+0000000021.avro" ,
46
+ " android_phone_acceleration/partition=0/android_phone_acceleration+0+0003018784.avro" ,
44
47
)
45
48
val targetFiles = resourceFiles.map { Paths .get(" in/$it " ) }
46
- resourceFiles.forEachIndexed { i, resourceFile ->
47
- javaClass.getResourceAsStream(" /$resourceFile " ).use { statusFile ->
48
- sourceClient.putObject(PutObjectArgs .Builder ().objectBuild(sourceConfig.bucket, targetFiles[i]) {
49
- stream(statusFile, - 1 , MAX_PART_SIZE )
50
- })
49
+ resourceFiles.mapIndexed { i, resourceFile ->
50
+ launch(Dispatchers .IO ) {
51
+ this @RestructureS3IntegrationTest.javaClass.getResourceAsStream(" /$resourceFile " )
52
+ .useSuspended { statusFile ->
53
+ sourceClient.putObject(PutObjectArgs .Builder ()
54
+ .objectBuild(sourceConfig.bucket, targetFiles[i]) {
55
+ stream(statusFile, - 1 , MAX_PART_SIZE )
56
+ })
57
+ }
51
58
}
52
- }
59
+ }.joinAll()
53
60
54
61
application.start()
55
62
56
63
val targetClient = targetConfig.createS3Client()
57
- val files = targetClient.listObjects(ListObjectsArgs .Builder ().bucketBuild(targetConfig.bucket) {
58
- prefix(" output" )
59
- recursive(true )
60
- useUrlEncodingType(false )
61
- })
62
- .map { it.get().objectName() }
63
- .toList()
64
64
65
65
application.redisHolder.execute { redis ->
66
- assertEquals(1L , redis.del(" offsets/application_server_status.json" ))
67
- assertEquals(1L , redis.del(" offsets/android_phone_acceleration.json" ))
66
+ launch { assertEquals(1L , redis.del(" offsets/application_server_status.json" )) }
67
+ launch { assertEquals(1L , redis.del(" offsets/android_phone_acceleration.json" )) }
68
68
}
69
69
70
70
val firstParticipantOutput = " output/STAGING_PROJECT/1543bc93-3c17-4381-89a5-c5d6272b827c/application_server_status"
71
71
val secondParticipantOutput = " output/radar-test-root/4ab9b985-6eec-4e51-9a29-f4c571c89f99/android_phone_acceleration"
72
- assertEquals(
73
- listOf (
74
- " $firstParticipantOutput /20200128_1300.csv" ,
75
- " $firstParticipantOutput /20200128_1400.csv" ,
76
- " $firstParticipantOutput /schema-application_server_status.json" ,
77
- " $secondParticipantOutput /20200528_1000.csv" ,
78
- " $secondParticipantOutput /schema-android_phone_acceleration.json" ),
79
- files)
80
72
81
- println (targetClient.getObject(GetObjectArgs .builder()
82
- .bucketBuild(targetConfig.bucket) {
83
- `object `(" $firstParticipantOutput /20200128_1300.csv" )
84
- }
85
- ).readBytes().toString(UTF_8 ))
86
-
87
- val csvContents = """
73
+ val files = coroutineScope {
74
+ launch(Dispatchers .IO ) {
75
+ val csvContents = """
88
76
key.projectId,key.userId,key.sourceId,value.time,value.serverStatus,value.ipAddress
89
77
STAGING_PROJECT,1543bc93-3c17-4381-89a5-c5d6272b827c,99caf236-bbe6-4eed-9c63-fba77349821d,1.58021982003E9,CONNECTED,
90
78
STAGING_PROJECT,1543bc93-3c17-4381-89a5-c5d6272b827c,99caf236-bbe6-4eed-9c63-fba77349821d,1.58021982003E9,CONNECTED,
91
79
92
80
""" .trimIndent()
93
- assertEquals(csvContents, targetClient.getObject(GetObjectArgs .Builder ()
94
- .bucketBuild(targetConfig.bucket) {
95
- `object `(" $firstParticipantOutput /20200128_1300.csv" )
96
- })
97
- .readBytes()
98
- .toString(UTF_8 ))
81
+ assertEquals(csvContents, targetClient.getObject(GetObjectArgs .Builder ()
82
+ .bucketBuild(targetConfig.bucket) {
83
+ `object `(" $firstParticipantOutput /20200128_1300.csv" )
84
+ })
85
+ .readBytes()
86
+ .toString(UTF_8 ))
87
+ }
99
88
100
- targetFiles.forEach {
101
- sourceClient.removeObject(RemoveObjectArgs .Builder ()
102
- .objectBuild(sourceConfig.bucket, it))
103
- }
104
- sourceClient.removeBucket(RemoveBucketArgs .Builder ().bucketBuild(sourceConfig.bucket))
105
- files.forEach {
106
- targetClient.removeObject(RemoveObjectArgs .Builder ().bucketBuild(targetConfig.bucket) {
107
- `object `(it)
108
- })
89
+ withContext(Dispatchers .IO ) {
90
+ targetClient.listObjects(ListObjectsArgs .Builder ()
91
+ .bucketBuild(targetConfig.bucket) {
92
+ prefix(" output" )
93
+ recursive(true )
94
+ useUrlEncodingType(false )
95
+ })
96
+ .map { it.get().objectName() }
97
+ .toHashSet()
98
+ }
109
99
}
110
- targetClient.removeBucket(RemoveBucketArgs .Builder ().bucketBuild(targetConfig.bucket))
111
100
101
+ assertEquals(
102
+ hashSetOf(
103
+ " $firstParticipantOutput /20200128_1300.csv" ,
104
+ " $firstParticipantOutput /20200128_1400.csv" ,
105
+ " $firstParticipantOutput /schema-application_server_status.json" ,
106
+ " $secondParticipantOutput /20200528_1000.csv" ,
107
+ " $secondParticipantOutput /schema-android_phone_acceleration.json" ,
108
+ ),
109
+ files,
110
+ )
111
+
112
+ coroutineScope {
113
+ // delete source files
114
+ launch {
115
+ targetFiles.map {
116
+ launch(Dispatchers .IO ) {
117
+ sourceClient.removeObject(RemoveObjectArgs .Builder ()
118
+ .objectBuild(sourceConfig.bucket, it))
119
+ }
120
+ }.joinAll()
121
+
122
+ launch(Dispatchers .IO ) {
123
+ sourceClient.removeBucket(RemoveBucketArgs .Builder ()
124
+ .bucketBuild(sourceConfig.bucket))
125
+ }
126
+ }
127
+
128
+ // delete target files
129
+ launch {
130
+ files.map {
131
+ launch(Dispatchers .IO ) {
132
+ targetClient.removeObject(RemoveObjectArgs .Builder ()
133
+ .bucketBuild(targetConfig.bucket) {
134
+ `object `(it)
135
+ })
136
+ }
137
+ }.joinAll()
138
+ launch(Dispatchers .IO ) {
139
+ targetClient.removeBucket(RemoveBucketArgs .Builder ()
140
+ .bucketBuild(targetConfig.bucket))
141
+ }
142
+ }
143
+ }
112
144
println (Timer )
113
145
}
114
146
}
0 commit comments