Skip to content

Commit e5c03b4

Browse files
committed
Add basic Vertex Java compilation tests
1 parent 8a72ed5 commit e5c03b4

File tree

2 files changed

+239
-0
lines changed

2 files changed

+239
-0
lines changed

firebase-vertexai/firebase-vertexai.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ android {
6464
}
6565
}
6666
lint { targetSdk = targetSdkVersion }
67+
sourceSets { getByName("test").java.srcDirs("src/testUtil") }
6768
}
6869

6970
// Enable Kotlin "Explicit API Mode". This causes the Kotlin compiler to fail if any
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package java.com.google.firebase.vertexai;
18+
19+
import android.graphics.Bitmap;
20+
import com.google.common.util.concurrent.ListenableFuture;
21+
import com.google.firebase.concurrent.FirebaseExecutors;
22+
import com.google.firebase.vertexai.FirebaseVertexAI;
23+
import com.google.firebase.vertexai.GenerativeModel;
24+
import com.google.firebase.vertexai.java.ChatFutures;
25+
import com.google.firebase.vertexai.java.GenerativeModelFutures;
26+
import com.google.firebase.vertexai.type.BlockReason;
27+
import com.google.firebase.vertexai.type.Candidate;
28+
import com.google.firebase.vertexai.type.Citation;
29+
import com.google.firebase.vertexai.type.CitationMetadata;
30+
import com.google.firebase.vertexai.type.Content;
31+
import com.google.firebase.vertexai.type.ContentModality;
32+
import com.google.firebase.vertexai.type.CountTokensResponse;
33+
import com.google.firebase.vertexai.type.FileDataPart;
34+
import com.google.firebase.vertexai.type.FinishReason;
35+
import com.google.firebase.vertexai.type.FunctionCallPart;
36+
import com.google.firebase.vertexai.type.GenerateContentResponse;
37+
import com.google.firebase.vertexai.type.HarmCategory;
38+
import com.google.firebase.vertexai.type.HarmProbability;
39+
import com.google.firebase.vertexai.type.HarmSeverity;
40+
import com.google.firebase.vertexai.type.ImagePart;
41+
import com.google.firebase.vertexai.type.InlineDataPart;
42+
import com.google.firebase.vertexai.type.ModalityTokenCount;
43+
import com.google.firebase.vertexai.type.Part;
44+
import com.google.firebase.vertexai.type.PromptFeedback;
45+
import com.google.firebase.vertexai.type.SafetyRating;
46+
import com.google.firebase.vertexai.type.TextPart;
47+
import com.google.firebase.vertexai.type.UsageMetadata;
48+
import java.util.Calendar;
49+
import java.util.List;
50+
import java.util.Map;
51+
import java.util.concurrent.Executor;
52+
import kotlinx.serialization.json.JsonElement;
53+
import kotlinx.serialization.json.JsonNull;
54+
import org.junit.Assert;
55+
import org.reactivestreams.Publisher;
56+
import org.reactivestreams.Subscriber;
57+
import org.reactivestreams.Subscription;
58+
59+
/**
60+
* Tests in this file exist to be compiled, not invoked
61+
*/
62+
public class JavaCompileTests {
63+
64+
public void initializeJava() throws Exception {
65+
FirebaseVertexAI vertex = FirebaseVertexAI.getInstance();
66+
GenerativeModel model = vertex.generativeModel("fake-model-name");
67+
GenerativeModelFutures futures = GenerativeModelFutures.from(model);
68+
testFutures(futures);
69+
}
70+
71+
private void testFutures(GenerativeModelFutures futures) throws Exception {
72+
Content content =
73+
new Content.Builder()
74+
.addText("Fake prompt")
75+
.addFileData("fakeuri", "image/png")
76+
.addInlineData(new byte[] {}, "text/json")
77+
.addImage(Bitmap.createBitmap(0, 0, Bitmap.Config.HARDWARE))
78+
.addPart(new FunctionCallPart("fakeFunction", Map.of("fakeArg", JsonNull.INSTANCE)))
79+
.build();
80+
Executor executor = FirebaseExecutors.directExecutor();
81+
ListenableFuture<CountTokensResponse> countResponse = futures.countTokens(content);
82+
validateCountTokensResponse(countResponse.get());
83+
ListenableFuture<GenerateContentResponse> generateResponse = futures.generateContent(content);
84+
validateGenerateContentResponse(generateResponse.get());
85+
ChatFutures chat = futures.startChat();
86+
ListenableFuture<GenerateContentResponse> future = chat.sendMessage(content);
87+
future.addListener(
88+
() -> {
89+
try {
90+
validateGenerateContentResponse(future.get());
91+
} catch (Exception e) {
92+
// Ignore
93+
}
94+
},
95+
executor);
96+
Publisher<GenerateContentResponse> responsePublisher = futures.generateContentStream(content);
97+
responsePublisher.subscribe(
98+
new Subscriber<GenerateContentResponse>() {
99+
private boolean complete = false;
100+
101+
@Override
102+
public void onSubscribe(Subscription s) {
103+
s.request(Long.MAX_VALUE);
104+
}
105+
106+
@Override
107+
public void onNext(GenerateContentResponse response) {
108+
Assert.assertFalse(complete);
109+
validateGenerateContentResponse(response);
110+
}
111+
112+
@Override
113+
public void onError(Throwable t) {
114+
// Ignore
115+
}
116+
117+
@Override
118+
public void onComplete() {
119+
complete = true;
120+
}
121+
});
122+
}
123+
124+
public void validateCountTokensResponse(CountTokensResponse response) {
125+
int tokens = response.getTotalTokens();
126+
Integer billable = response.getTotalBillableCharacters();
127+
Assert.assertEquals(tokens, response.component1());
128+
Assert.assertEquals(billable, response.component2());
129+
Assert.assertEquals(response.getPromptTokensDetails(), response.component3());
130+
for (ModalityTokenCount count : response.getPromptTokensDetails()) {
131+
ContentModality modality = count.getModality();
132+
int tokenCount = count.getTokenCount();
133+
}
134+
}
135+
136+
public void validateGenerateContentResponse(GenerateContentResponse response) {
137+
List<Candidate> candidates = response.getCandidates();
138+
if (candidates.size() == 1
139+
&& candidates.get(0).getContent().getParts().stream()
140+
.anyMatch(p -> p instanceof TextPart && !((TextPart) p).getText().isEmpty())) {
141+
String text = response.getText();
142+
Assert.assertNotNull(text);
143+
Assert.assertFalse(text.isBlank());
144+
}
145+
validateCandidates(candidates);
146+
validateFunctionCalls(response.getFunctionCalls());
147+
validatePromptFeedback(response.getPromptFeedback());
148+
validateUsageMetadata(response.getUsageMetadata());
149+
}
150+
151+
public void validateCandidates(List<Candidate> candidates) {
152+
for (Candidate candidate : candidates) {
153+
validateCitationMetadata(candidate.getCitationMetadata());
154+
FinishReason reason = candidate.getFinishReason();
155+
validateSafetyRatings(candidate.getSafetyRatings());
156+
validateCitationMetadata(candidate.getCitationMetadata());
157+
validateContent(candidate.getContent());
158+
}
159+
}
160+
161+
public void validateContent(Content content) {
162+
String role = content.getRole();
163+
for (Part part : content.getParts()) {
164+
if (part instanceof TextPart) {
165+
String text = ((TextPart) part).getText();
166+
} else if (part instanceof ImagePart) {
167+
Bitmap bitmap = ((ImagePart) part).getImage();
168+
} else if (part instanceof InlineDataPart) {
169+
String mime = ((InlineDataPart) part).getMimeType();
170+
byte[] data = ((InlineDataPart) part).getInlineData();
171+
} else if (part instanceof FileDataPart) {
172+
String mime = ((FileDataPart) part).getMimeType();
173+
String uri = ((FileDataPart) part).getUri();
174+
}
175+
}
176+
}
177+
178+
public void validateCitationMetadata(CitationMetadata metadata) {
179+
if (metadata != null) {
180+
for (Citation citation : metadata.getCitations()) {
181+
String uri = citation.getUri();
182+
String license = citation.getLicense();
183+
Calendar calendar = citation.getPublicationDate();
184+
int startIndex = citation.getStartIndex();
185+
int endIndex = citation.getEndIndex();
186+
Assert.assertTrue(startIndex <= endIndex);
187+
}
188+
}
189+
}
190+
191+
public void validateFunctionCalls(List<FunctionCallPart> parts) {
192+
if (parts != null) {
193+
for (FunctionCallPart part : parts) {
194+
String functionName = part.getName();
195+
Map<String, JsonElement> args = part.getArgs();
196+
Assert.assertFalse(functionName.isBlank());
197+
}
198+
}
199+
}
200+
201+
public void validatePromptFeedback(PromptFeedback feedback) {
202+
if (feedback != null) {
203+
String message = feedback.getBlockReasonMessage();
204+
BlockReason reason = feedback.getBlockReason();
205+
validateSafetyRatings(feedback.getSafetyRatings());
206+
}
207+
}
208+
209+
public void validateSafetyRatings(List<SafetyRating> ratings) {
210+
for (SafetyRating rating : ratings) {
211+
Boolean blocked = rating.getBlocked();
212+
HarmCategory category = rating.getCategory();
213+
HarmProbability probability = rating.getProbability();
214+
float score = rating.getProbabilityScore();
215+
HarmSeverity severity = rating.getSeverity();
216+
Float severityScore = rating.getSeverityScore();
217+
if (severity != null) {
218+
Assert.assertNotNull(severityScore);
219+
}
220+
}
221+
}
222+
223+
public void validateUsageMetadata(UsageMetadata metadata) {
224+
if (metadata != null) {
225+
int totalTokens = metadata.getTotalTokenCount();
226+
int promptTokenCount = metadata.getPromptTokenCount();
227+
for (ModalityTokenCount count : metadata.getPromptTokensDetails()) {
228+
ContentModality modality = count.getModality();
229+
int tokenCount = count.getTokenCount();
230+
}
231+
Integer candidatesTokenCount = metadata.getCandidatesTokenCount();
232+
for (ModalityTokenCount count : metadata.getCandidatesTokensDetails()) {
233+
ContentModality modality = count.getModality();
234+
int tokenCount = count.getTokenCount();
235+
}
236+
}
237+
}
238+
}

0 commit comments

Comments
 (0)