Skip to content

Commit 6d7303f

Browse files
committed
closes #66 ChainLP: Storage support: DB
1 parent ce7aa47 commit 6d7303f

File tree

17 files changed

+110
-52
lines changed

17 files changed

+110
-52
lines changed

Config.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ chaintest.generator.chainlp.host.url=http://localhost/
2121
chaintest.generator.chainlp.client.request-timeout-s=30
2222
chaintest.generator.chainlp.client.expect-continue=false
2323
chaintest.generator.chainlp.client.max-retries=3
24+
chaintest.generator.chainlp.persist-embeds=true
2425

2526
## simple
2627
chaintest.generator.simple.enabled=true

chainlp/backend/chainlp/src/main/java/com/aventstack/chainlp/ChainApp.java

+2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.cache.annotation.EnableCaching;
56

7+
@EnableCaching
68
@SpringBootApplication
79
public class ChainApp {
810

chainlp/backend/chainlp/src/main/java/com/aventstack/chainlp/api/test/Embed.java

+11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import jakarta.persistence.GeneratedValue;
77
import jakarta.persistence.GenerationType;
88
import jakarta.persistence.Id;
9+
import jakarta.persistence.Lob;
910
import jakarta.persistence.ManyToOne;
1011
import jakarta.persistence.Table;
1112
import jakarta.persistence.Transient;
@@ -35,7 +36,17 @@ public class Embed {
3536
@Column
3637
private String url;
3738

39+
@Column(columnDefinition = "longblob")
40+
@Lob
41+
private byte[] bytes;
42+
43+
@Column
44+
private String base64;
45+
3846
@Transient
3947
private String presigned;
4048

49+
@Transient
50+
private boolean store;
51+
4152
}

chainlp/backend/chainlp/src/main/java/com/aventstack/chainlp/api/test/Test.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import lombok.ToString;
2323
import org.springframework.data.annotation.CreatedDate;
2424

25+
import java.util.Base64;
2526
import java.util.HashSet;
2627
import java.util.List;
2728
import java.util.Set;
@@ -31,7 +32,7 @@
3132
@Builder
3233
@NoArgsConstructor
3334
@AllArgsConstructor
34-
@ToString(exclude = { "parent" })
35+
@ToString(exclude = { "parent", "embeds" })
3536
@Table(name = "test")
3637
public class Test {
3738

@@ -125,7 +126,19 @@ public void setChildren(List<Test> children) {
125126
public void setEmbeds(final List<Embed> embeds) {
126127
this.embeds = embeds;
127128
if (embeds != null) {
128-
embeds.forEach(x -> x.setTest(this));
129+
for (final Embed embed : embeds) {
130+
embed.setTest(this);
131+
if (embed.isStore()) {
132+
if (null != embed.getBase64() && !embed.getBase64().isEmpty()) {
133+
final byte[] data = Base64.getDecoder().decode(embed.getBase64().getBytes());
134+
embed.setBytes(data);
135+
embed.setBase64(null);
136+
}
137+
} else {
138+
embed.setBase64(null);
139+
embed.setBytes(null);
140+
}
141+
}
129142
}
130143
}
131144

chainlp/backend/chainlp/src/main/java/com/aventstack/chainlp/api/test/TestService.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,12 @@ public Page<Test> findAll(final Test test, final String op, final Pageable pagea
6363
}
6464

6565
private Test resolveEmbeds(final Test test) {
66-
for (final Embed embed : test.getEmbeds()) {
67-
final String presigned = embedResolver.getResolver(embed.getUrl())
68-
.resolve(embed.getUrl());
69-
embed.setPresigned(presigned);
66+
if (test.getEmbeds().stream().anyMatch(x -> null != x.getUrl() && !x.getUrl().isBlank())) {
67+
for (final Embed embed : test.getEmbeds()) {
68+
final String presigned = embedResolver.getResolver(embed.getUrl())
69+
.resolve(embed.getUrl());
70+
embed.setPresigned(presigned);
71+
}
7072
}
7173
test.getChildren().forEach(this::resolveEmbeds);
7274
return test;

chainlp/backend/chainlp/src/main/java/com/aventstack/chainlp/embed/AwsS3SignedUrlResolver.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public String createPresignedGetUrl(final String bucket, final String key) {
4040
.key(key)
4141
.build();
4242
final GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder()
43-
.signatureDuration(Duration.ofMinutes(10))
43+
.signatureDuration(Duration.ofDays(1))
4444
.getObjectRequest(objectRequest)
4545
.build();
4646
final PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(presignRequest);

chainlp/frontend/chainlp/src/app/components/test/test.component.html

+8-2
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,18 @@ <h5 class="mb-3 testname" [ngClass]="test.result.toLowerCase()">{{test.name}}</h
6060
<pre>{{leaf.error}}</pre>
6161
</div>
6262
<div class="mt-2 screenshots" *ngIf="leaf.embeds && leaf.embeds.length">
63-
<img *ngFor="let s of leaf.embeds" [src]="s.presigned || s.url" class="img-fluid" alt="screenshot" />
63+
<ng-container *ngFor="let s of leaf.embeds">
64+
<img *ngIf="s.presigned || s.url" [src]="s.presigned || s.url" class="img-fluid" alt="screenshot" />
65+
<img *ngIf="s.bytes || s.base64" [src]="'data:image/png;base64,' + s.bytes || s.base64" class="img-fluid" alt="screenshot" />
66+
</ng-container>
6467
</div>
6568
</div>
6669
</div>
6770
<div class="mt-2 screenshots" *ngIf="child.embeds && child.embeds.length">
68-
<img *ngFor="let s of child.embeds" [src]="s.presigned || s.url" class="img-fluid" alt="screenshot" />
71+
<ng-container *ngFor="let s of child.embeds">
72+
<img *ngIf="s.presigned || s.url" [src]="s.presigned || s.url" class="img-fluid" alt="screenshot" />
73+
<img *ngIf="s.bytes || s.base64" [src]="'data:image/png;base64,' + s.bytes || s.base64" class="img-fluid" alt="screenshot" />
74+
</ng-container>
6975
</div>
7076
</div>
7177
</div>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export class Embed {
22
presigned: string;
33
url: string;
4+
bytes: any;
5+
base64: string;
46
}

chainlp/frontend/chainlp/src/app/pages/build/build/build.component.html

+8-2
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,10 @@ <h5 class="mb-3 testname" [ngClass]="test.result.toLowerCase()">{{test.name}}</h
220220
<pre>{{leaf.error}}</pre>
221221
</div>
222222
<div class="mt-2 mb-4 screenshots" *ngIf="leaf.embeds && leaf.embeds.length">
223-
<img *ngFor="let s of leaf.embeds" [src]="s.presigned || s.url" class="img-fluid" alt="screenshot" />
223+
<ng-container *ngFor="let s of leaf.embeds">
224+
<img *ngIf="s.presigned || s.url" [src]="s.presigned || s.url" class="img-fluid" alt="screenshot" />
225+
<img *ngIf="s.bytes || s.base64" [src]="'data:image/png;base64,' + s.bytes || s.base64" class="img-fluid" alt="screenshot" />
226+
</ng-container>
224227
</div>
225228
</div>
226229
</div>
@@ -231,7 +234,10 @@ <h5 class="mb-3 testname" [ngClass]="test.result.toLowerCase()">{{test.name}}</h
231234
<pre>{{child.error}}</pre>
232235
</div>
233236
<div class="mt-2 screenshots" *ngIf="child.embeds && child.embeds.length">
234-
<img *ngFor="let s of child.embeds" [src]="s.presigned || s.url" class="img-fluid" alt="screenshot" />
237+
<ng-container *ngFor="let s of child.embeds">
238+
<img *ngIf="s.presigned || s.url" [src]="s.presigned || s.url" class="img-fluid" alt="screenshot" />
239+
<img *ngIf="s.bytes || s.base64" [src]="'data:image/png;base64,' + s.bytes || s.base64" class="img-fluid" alt="screenshot" />
240+
</ng-container>
235241
</div>
236242
</div>
237243
</div>

core/chaintest-core-java/src/main/java/com/aventstack/chaintest/domain/Embed.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.aventstack.chaintest.domain;
22

3-
import lombok.Data;
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import lombok.Getter;
45
import lombok.NoArgsConstructor;
6+
import lombok.Setter;
57
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
79

@@ -13,8 +15,10 @@
1315
import java.util.List;
1416
import java.util.UUID;
1517

16-
@Data
18+
@Getter
19+
@Setter
1720
@NoArgsConstructor
21+
@JsonIgnoreProperties(ignoreUnknown = true)
1822
public class Embed {
1923

2024
private static final Logger log = LoggerFactory.getLogger(Embed.class);
@@ -30,10 +34,12 @@ public class Embed {
3034
);
3135

3236
private final UUID uuid = UUID.randomUUID();
37+
private String url;
3338
private String base64;
3439
private File file;
3540
private byte[] bytes;
3641
private String mediaType;
42+
private boolean store = true;
3743

3844
public Embed(final String base64, final String mediaType) {
3945
this.base64 = base64;

core/chaintest-core-java/src/main/java/com/aventstack/chaintest/domain/Test.java

+1-14
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.aventstack.chaintest.util.TimeUtil;
55
import com.fasterxml.jackson.annotation.JsonIgnore;
66
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
7-
import com.fasterxml.jackson.annotation.JsonProperty;
87
import lombok.Getter;
98
import lombok.Setter;
109

@@ -28,9 +27,9 @@
2827
* class name, start and end times, result, tags, error details, and child tests.
2928
* It also provides methods to complete the test and update its statistics.
3029
*/
31-
@JsonIgnoreProperties(ignoreUnknown = true)
3230
@Getter
3331
@Setter
32+
@JsonIgnoreProperties(ignoreUnknown = true)
3433
public class Test implements ChainTestEntity {
3534

3635
/**
@@ -116,7 +115,6 @@ public class Test implements ChainTestEntity {
116115
/**
117116
* The embedded media associated with the test.
118117
*/
119-
@JsonIgnore
120118
private final List<Embed> embeds = new ArrayList<>();
121119

122120
/**
@@ -132,9 +130,6 @@ public class Test implements ChainTestEntity {
132130
@JsonIgnore
133131
private Test parent;
134132

135-
@JsonProperty("embeds")
136-
private final List<BasicEmbed> basicEmbeds = new ArrayList<>();
137-
138133
/**
139134
* Default constructor.
140135
*/
@@ -453,12 +448,4 @@ public void addEmbed(final Embed embed) {
453448
embeds.add(embed);
454449
}
455450

456-
public void addScreenshotURL(final String url) {
457-
addBasicEmbed(url);
458-
}
459-
460-
public void addBasicEmbed(final String url) {
461-
basicEmbeds.add(new BasicEmbed(url));
462-
}
463-
464451
}

core/chaintest-core-java/src/main/java/com/aventstack/chaintest/generator/ChainLPGenerator.java

+16
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class ChainLPGenerator implements Generator {
2323
private static final Logger log = LoggerFactory.getLogger(ChainLPGenerator.class);
2424
private static final String NAME = "chainlp";
2525
private static final String HTTP_CLIENT_ENABLED = "chaintest.generator.chainlp.enabled";
26+
private static final String SEND_EMBEDS = "chaintest.generator.chainlp.persist-embeds";
2627
private static final ConcurrentHashMap<String, WrappedResponseAsync<Test>> _wrappedResponses = new ConcurrentHashMap<>();
2728
private static final AtomicBoolean CALLBACK_INVOKED = new AtomicBoolean();
2829

@@ -32,6 +33,7 @@ public class ChainLPGenerator implements Generator {
3233
private ChainTestApiClient _client;
3334
private Build _build;
3435
private Queue<Test> _tests;
36+
private boolean _sendEmbeds = true;
3537

3638
public ChainLPGenerator(final String testRunner) {
3739
_testRunner = testRunner;
@@ -101,6 +103,11 @@ public void start(final Optional<Map<String, String>> config, final String testR
101103
_build.setProjectId(buildReq.getProjectId());
102104
CALLBACK_INVOKED.set(true);
103105
log.debug("All tests in this run will be associated with buildId: {}", _build.getId());
106+
107+
final String sendEmbeds = config.get().get(SEND_EMBEDS);
108+
if (null != sendEmbeds && !sendEmbeds.isEmpty()) {
109+
_sendEmbeds = Boolean.parseBoolean(sendEmbeds);
110+
}
104111
}
105112
} catch (final IOException | InterruptedException e) {
106113
log.debug("Failed to send Build. PluginService will shutdown and " +
@@ -149,6 +156,10 @@ public void afterTest(final Test test, final Optional<Throwable> throwable) {
149156

150157
updateAttributes(test);
151158

159+
if (!_sendEmbeds) {
160+
setEmbedStorableState(test);
161+
}
162+
152163
final WrappedResponseAsync<Test> wrapper = new WrappedResponseAsync<>(test);
153164
_wrappedResponses.put(test.getClientId().toString(), wrapper);
154165
try {
@@ -159,6 +170,11 @@ public void afterTest(final Test test, final Optional<Throwable> throwable) {
159170
}
160171
}
161172

173+
private void setEmbedStorableState(final Test test) {
174+
test.getEmbeds().forEach(embed -> embed.setStore(false));
175+
test.getChildren().forEach(this::setEmbedStorableState);
176+
}
177+
162178
private void updateAttributes(final Test test) {
163179
test.setBuildId(_build.getId());
164180
test.setProjectId(_build.getProjectId());

core/chaintest-core-java/src/main/java/com/aventstack/chaintest/storage/AWSS3Client.java

+13-12
Original file line numberDiff line numberDiff line change
@@ -81,45 +81,46 @@ private void createBucket(final String bucketName) {
8181
}
8282

8383
@Override
84-
public void upload(final Test test, final String key, final byte[] data) {
84+
public String upload(final Test test, final String key, final byte[] data) {
8585
final String prefixKey = getPrefixKey(_prefix, key);
8686
_client.putObject(PutObjectRequest.builder().bucket(_bucket).key(prefixKey)
8787
.build(),
8888
RequestBody.fromBytes(data));
89-
assignURL(test, prefixKey);
89+
return getUrl(test, prefixKey);
9090
}
9191

92-
private void assignURL(final Test test, final String key) {
93-
test.addScreenshotURL(
94-
_client.utilities().getUrl(builder -> builder.bucket(_bucket).key(key)).toExternalForm());
92+
private String getUrl(final Test test, final String key) {
93+
return _client.utilities().getUrl(builder -> builder.bucket(_bucket).key(key)).toExternalForm();
9594
}
9695

9796
@Override
98-
public void upload(final Test test, String key, String base64) {
97+
public String upload(final Test test, String key, String base64) {
9998
final byte[] data = Base64.getDecoder().decode(base64.getBytes());
100-
upload(test, key, data);
99+
return upload(test, key, data);
101100
}
102101

103102
@Override
104-
public void upload(final Test test, final String key, final File file) {
103+
public String upload(final Test test, final String key, final File file) {
105104
final String prefixKey = getPrefixKey(_prefix, key);
106105
_client.putObject(PutObjectRequest.builder().bucket(_bucket).key(prefixKey)
107106
.build(),
108107
RequestBody.fromFile(file));
109-
assignURL(test, prefixKey);
108+
return getUrl(test, prefixKey);
110109
}
111110

112111
@Override
113112
public void upload(final Test test, Embed embed) {
113+
String url = null;
114114
if (null != embed.getBytes()) {
115-
upload(test, embed.getName(), embed.getBytes());
115+
url = upload(test, embed.getName(), embed.getBytes());
116116
} else if (null != embed.getBase64() && !embed.getBase64().isBlank()) {
117-
upload(test, embed.getName(), embed.getBase64());
117+
url = upload(test, embed.getName(), embed.getBase64());
118118
} else if (null != embed.getFile()) {
119-
upload(test, embed.getName(), embed.getFile());
119+
url = upload(test, embed.getName(), embed.getFile());
120120
} else {
121121
log.error("Unable to upload Embed to Azure Blob Storage. Source missing");
122122
}
123+
embed.setUrl(url);
123124
}
124125

125126
@Override

0 commit comments

Comments
 (0)