/*
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.firebase.testing;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.io.CharStreams;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.TestOnlyImplFirebaseTrampolines;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.internal.GetTokenResult;
import com.google.firebase.tasks.Task;
import com.google.firebase.tasks.Tasks;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
public class IntegrationTestUtils {
private static JSONObject IT_SERVICE_ACCOUNT;
private static FirebaseApp masterApp;
private static synchronized JSONObject ensureServiceAccount() {
if (IT_SERVICE_ACCOUNT == null) {
String certificatePath = System.getProperty("firebase.it.certificate");
checkArgument(!Strings.isNullOrEmpty(certificatePath),
"Service account certificate path not set. Set the "
+ "file.it.certificate system property and try again.");
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(certificatePath))) {
IT_SERVICE_ACCOUNT = new JSONObject(CharStreams.toString(reader));
} catch (IOException e) {
throw new RuntimeException("Failed to read service account certificate", e);
}
}
return IT_SERVICE_ACCOUNT;
}
public static InputStream getServiceAccountCertificate() {
return new ByteArrayInputStream(ensureServiceAccount().toString().getBytes());
}
public static String getProjectId() {
return ensureServiceAccount().get("project_id").toString();
}
public static String getDatabaseUrl() {
return "https://" + getProjectId() + ".firebaseio.com";
}
/**
* Initializes the default FirebaseApp for integration testing (if not already initialized), and
* returns it. Integration tests that interact with the default FirebaseApp should call this
* method to obtain the app instance. This method ensures that all integration tests get the
* same FirebaseApp instance, instead of initializing an app per test.
*
* @return the default FirebaseApp instance
*/
public static synchronized FirebaseApp ensureDefaultApp() {
if (masterApp == null) {
FirebaseOptions options =
new FirebaseOptions.Builder()
.setDatabaseUrl(getDatabaseUrl())
.setCredential(TestUtils.getCertCredential(getServiceAccountCertificate()))
.build();
masterApp = FirebaseApp.initializeApp(options);
}
return masterApp;
}
public static FirebaseApp initApp(String name) {
FirebaseOptions options =
new FirebaseOptions.Builder()
.setDatabaseUrl(getDatabaseUrl())
.setCredential(TestUtils.getCertCredential(getServiceAccountCertificate()))
.build();
return FirebaseApp.initializeApp(options, name);
}
public static DatabaseReference getRandomNode(FirebaseApp app) {
return getRandomNode(app, 1).get(0);
}
public static List<DatabaseReference> getRandomNode(FirebaseApp app, int count) {
FirebaseDatabase database = FirebaseDatabase.getInstance(app);
ImmutableList.Builder<DatabaseReference> builder = ImmutableList.builder();
String name = null;
for (int i = 0; i < count; i++) {
if (name == null) {
DatabaseReference ref = database.getReference().push();
builder.add(ref);
name = ref.getKey();
} else {
builder.add(database.getReference().child(name));
}
}
return builder.build();
}
public static class AppHttpClient {
private final FirebaseApp app;
public AppHttpClient() {
this(FirebaseApp.getInstance());
}
public AppHttpClient(FirebaseApp app) {
this.app = checkNotNull(app);
}
public ResponseInfo put(String path, String data) throws IOException {
String url = app.getOptions().getDatabaseUrl() + path + "?access_token=" + getToken();
HttpPut put = new HttpPut(url);
HttpEntity entity = new StringEntity(data, "UTF-8");
put.setEntity(entity);
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(put);
return new ResponseInfo(response);
}
private String getToken() {
// TODO: We should consider exposing getToken (or similar) publicly for the
// purpose of servers doing authenticated REST requests like this.
Task<GetTokenResult> task = TestOnlyImplFirebaseTrampolines.getToken(app, false);
try {
return Tasks.await(task).getToken();
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static class ResponseInfo {
private final int status;
private final byte[] payload;
private ResponseInfo(HttpResponse response) throws IOException {
this.status = response.getStatusLine().getStatusCode();
this.payload = EntityUtils.toByteArray(response.getEntity());
}
public int getStatus() {
return status;
}
public byte[] getPayload() {
return payload;
}
}
}