Skip to content

Commit

Permalink
run testapp prod
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasht86 committed Jul 3, 2024
1 parent 58d0a31 commit c6dc914
Show file tree
Hide file tree
Showing 18 changed files with 572 additions and 0 deletions.
57 changes: 57 additions & 0 deletions .github/workflows/deploy-with-java.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

name: pyvespa - Build and Deploy with Java - Github Action

on:
workflow_dispatch:
push:
branches:
- thomasht86/tests-to-github-action

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Vespa uses Java 17
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
# Find Vespa version of current production deployment
- name: Find compile version
working-directory: tests/testapps/production-deployment-with-tests-java
run: mvn -B clean vespa:compileVersion -DapiKey="${VESPA_TEAM_VESPACLOUD_DOCSEARCH_API_KEY}"

# Build the application package and the tester bundle
- name: Build with Maven
working-directory: tests/testapps/production-deployment-with-tests-java
run: mvn -B package -Dvespa.compile.version="$(cat target/vespa.compile.version)"

# Upload artifacts to be used in the deploy job
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
path: target/*
name: applicationpackage

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip" # caching pip dependencies
- name: Install dependencies
run: pip install pyvespa vespacli

- name: Deploy to prod
env:
VESPA_TEAM_API_KEY: ${{ secrets.VESPA_TEAM_API_KEY }}
run: |
python .github/workflows/deploy_to_prod.py \
--tenant vespa-team \
--application testapp \
--api-key $VESPA_TEAM_API_KEY \
--application-root tests/testapps/production-deployment-with-tests-java/target/ \
--max-wait 3600 \
--source-url "$(git config --get remote.origin.url | sed 's+git@\(.*\):\(.*\)\.git+https://\1/\2+')/commit/$(git rev-parse HEAD)"
37 changes: 37 additions & 0 deletions .github/workflows/deploy_to_prod.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Command line script to deploy Vespa applications to Vespa Cloud
# Usage: vespa-deploy.py --tenant --application --api-key --application-root --max-wait 3600 --source-url

import argparse

from vespa.deployment import VespaCloud


def deploy_prod(
tenant, application, api_key, application_root, max_wait=3600, source_url=None
):
vespa_cloud = VespaCloud(
tenant=tenant,
application=application,
key_content=api_key,
)
build_no = vespa_cloud.deploy_to_prod(application_root, source_url=source_url)
vespa_cloud.wait_for_prod_deployment(build_no, max_wait=max_wait)


if __name__ == "__main__":
args = argparse.ArgumentParser()
args.add_argument("--tenant", required=True, help="Vespa Cloud tenant")
args.add_argument("--application", required=True, help="Vespa Cloud application")
args.add_argument("--api-key", required=True, help="Vespa Cloud API key")
args.add_argument(
"--application-root", required=True, help="Path to the Vespa application root"
)
args.add_argument(
"--max-wait", type=int, default=3600, help="Max wait time in seconds"
)
args.add_argument(
"--source-url", help="Source URL (git commit URL) for the deployment"
)

args = args.parse_args()
deploy_prod(args.tenant, args.application, args.api_key, args.application_root)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea/
target/
52 changes: 52 additions & 0 deletions tests/testapps/production-deployment-with-tests-java/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!-- Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->

![Vespa Cloud logo](https://cloud.vespa.ai/assets/logos/vespa-cloud-logo-full-black.png)

# Production Deployment with Java Tests

A minimal Vespa Cloud application for deployment into a Production zone - with basic Java-tests.

An application using Java test code must be deployed using the procedure for
[production deployment with components](https://cloud.vespa.ai/en/production-deployment#production-deployment-with-components) -
steps:

```
vespa config set target cloud
vespa config set application mytenant.myapp.myinstance
vespa auth login
mvn clean
vespa auth cert -f
mvn vespa:compileVersion -Dtenant=mytenant -Dapplication=myapp
mvn -U package -Dvespa.compile.version="$(cat target/vespa.compile.version)"
vespa prod deploy
```


## Developing system and staging tests
Develop tests using an instance in the Dev zone.
Use the Console and upload `target/application.zip` built in the steps above - use "default" instance name.

mvn test -D test.categories=system \
-D vespa.test.config=ext/test-config.json \
-D dataPlaneCertificateFile=data-plane-public-cert.pem \
-D dataPlaneKeyFile=data-plane-private-key.pem

mvn test -D test.categories=staging-setup \
-D vespa.test.config=ext/test-config.json \
-D dataPlaneCertificateFile=data-plane-public-cert.pem \
-D dataPlaneKeyFile=data-plane-private-key.pem

mvn test -D test.categories=staging \
-D vespa.test.config=ext/test-config.json \
-D dataPlaneCertificateFile=data-plane-public-cert.pem \
-D dataPlaneKeyFile=data-plane-private-key.pem


One can also use a local instance:

mvn test -D test.categories=system -D vespa.test.config=ext/test-config-local.json
mvn test -D test.categories=staging-setup -D vespa.test.config=ext/test-config-local.json
mvn test -D test.categories=staging -D vespa.test.config=ext/test-config-local.json

See [Vespa Cloud Automated Deployments](https://cloud.vespa.ai/en/automated-deployments)
for an overview of production deployments.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"localEndpoints": {
"default" : "http://localhost:8080/"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"localEndpoints": {
"default" : "https://default.myapp.mytenant.aws-us-east-1c.dev.z.vespa-app.cloud/"
}
}
27 changes: 27 additions & 0 deletions tests/testapps/production-deployment-with-tests-java/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0"?>
<!-- Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ai.vespa.example</groupId>
<artifactId>tests</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>demo</module>
</modules>

<parent>
<groupId>com.yahoo.vespa</groupId>
<artifactId>cloud-tenant-base</artifactId>
<version>[8,9)</version>
<relativePath />
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
<deployment version="1.0">
<prod>
<region>aws-us-east-1c</region>
</prod>
</deployment>

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

# A description of a type of data, how to store and index it, and what to compute over the data elements
#
# See:
# - https://docs.vespa.ai/en/schemas.html
schema music {

document music {

field artist type string {
indexing: summary | index
}

field album type string {
indexing: summary | index
}

field year type int {
indexing: summary | attribute
}

field category_scores type tensor<float>(cat{}) {
indexing: summary | attribute
}

}

fieldset default {
fields: artist, album
}

# Rank profiles defines what to compute over the data, and how to use the computation result to order them
# They can be selected at query time (ranking.profile=[name]), and can be everything from simple handwritten
# expressions as below to references to large machine-learned models.
#
# See
# - https://docs.vespa.ai/en/ranking.html
rank-profile rank_albums inherits default {
inputs {
query(user_profile) tensor<float>(cat{})
}
first-phase {
expression: sum(query(user_profile) * attribute(category_scores))
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
<services version="1.0">

<container id="default" version="1.0">
<document-api/>
<search/>
<nodes count="2">
<resources vcpu="2" memory="8Gb" disk="1Tb"/>
</nodes>
</container>

<content id="music" version="1.0">
<min-redundancy>2</min-redundancy>
<documents>
<document type="music" mode="index" />
</documents>
<nodes count="2">
<resources vcpu="2" memory="8Gb" disk="1Tb"/>
</nodes>
</content>

</services>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package ai.vespa.example.album;

import com.yahoo.application.Application;
import com.yahoo.application.Networking;

import java.nio.file.FileSystems;
import java.util.Objects;

/**
* This uses the Application class to set up a container instance of this application
* in this JVM. All other aspects of the application package than a single container
* cluster is ignored. This is useful for e.g starting a container instance in your IDE
* and serving real HTTP requests for interactive debugging.
* <p>
* After running main you can e.g open
* http://localhost:8080/search/?query=title:foo&tracelevel=2
* in a browser.
*/
public class ApplicationMain {

public static void main(String[] args) throws Exception {
try (Application app = Application.fromApplicationPackage(FileSystems.getDefault().getPath("src/main/application"),
Networking.enable)) {
Objects.requireNonNull(app);
Thread.sleep(Long.MAX_VALUE);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package ai.vespa.example.album;

import ai.vespa.hosted.cd.Endpoint;
import ai.vespa.hosted.cd.SystemTest;
import ai.vespa.hosted.cd.TestRuntime;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestReporter;

import java.io.IOException;
import java.net.http.HttpResponse;
import java.util.Map;

import static java.net.http.HttpRequest.BodyPublishers.ofString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

@SystemTest
class FeedAndSearchSystemTest {

private final Endpoint endpoint = TestRuntime.get().deploymentToTest().endpoint("default");

@Test
void testOutput(TestReporter testReporter) {
testReporter.publishEntry("Hello from an empty test!");
assertTrue(true, "Text from assertion for comparison");
}

@Test
void feedAndSearch() throws IOException {
String documentPath = "/document/v1/mynamespace/music/docid/test1";
String deleteAll = "/document/v1/mynamespace/music/docid?selection=true&cluster=music";
String document = """
{
"fields": {
"artist": "Coldplay"
}
}""";
String yql = "SELECT * FROM music WHERE artist CONTAINS 'coldplay'";

HttpResponse<String> deleteResult = endpoint.send(endpoint.request(deleteAll).DELETE());
assertEquals(200, deleteResult.statusCode());

// the first query needs a higher timeout than the default 500ms, to warm up the code
HttpResponse<String> emptyResult = endpoint.send(endpoint.request("/search/",
Map.of("yql", yql,
"timeout", "10s")));
assertEquals(200, emptyResult.statusCode());
assertEquals(0, new ObjectMapper().readTree(emptyResult.body())
.get("root").get("fields").get("totalCount").asLong());

HttpResponse<String> feedResult = endpoint.send(endpoint.request(documentPath)
.POST(ofString(document)));
assertEquals(200, feedResult.statusCode());

HttpResponse<String> searchResult = endpoint.send(endpoint.request("/search/",
Map.of("yql", yql)));
assertEquals(200, searchResult.statusCode());
assertEquals(1, new ObjectMapper().readTree(searchResult.body())
.get("root").get("fields").get("totalCount").asLong());
}
}
Loading

0 comments on commit c6dc914

Please sign in to comment.