Skip to content
This repository has been archived by the owner on Jan 9, 2020. It is now read-only.

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
MishUshakov committed Apr 27, 2019
0 parents commit 4eba477
Show file tree
Hide file tree
Showing 10 changed files with 549 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bin
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM scratch
COPY bin/fulfillment-tester-linux /
COPY ui /ui
VOLUME ["/tmp"]
ENTRYPOINT ["/fulfillment-tester-linux"]
7 changes: 7 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2019 Ushakov

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Dialogflow Fulfillment Tester

Test your Fulfillments like never before!

Start it:

![](https://i.imgur.com/Y5Ufr32.png)

And test with style using the User Interface:

![](https://i.imgur.com/YSulY94.png)

Or send the requests manually:

![](https://i.imgur.com/ywbIjrE.jpg)

## Features

- Works on Windows, Linux and Mac (64 bit)
- Small binary with no external dependencies, written in Go (<10 MB)
- Supports fulfillments in any programming language
- Supports Actions on Google fulfillments
- No More waiting. Never. Just run your fulfillment (locally or remotely) and start testing
- Be 100x more productive, when working with multiple Agents
- Run automated tests with tools like Jest, Ava, Mocha (or any other of your choice)
- Test with convinience, with a built-in User Interface
- Test your fulfillments on CI/CD
- Debug your fulfillments: run tests, fix errors, repeat
- Isolate your testing (great, when working in a group). Don't share access to your Google Project
- Can be packaged as Docker image and run on Docker or Kubernetes
- Works exactly like Dialogflow, 100% accurate testing results guaranteed

Excited? Let's get started!

## Installation

Connect your Dialogflow Agent to [Dialogflow Gateway](https://dialogflow.cloud.ushakov.co), read the guide [here](https://github.com/mishushakov/dialogflow-gateway-docs/blob/master/guide.md)

Install the latest executable for your operating system from the [Releases Page](https://github.com/mishushakov/dialogflow-fulfillment-tester/releases)

Run

```sh
dialogflow-fulfillment-tester --project <YOUR GOOGLE CLOUD PROJECT ID> --fulfillment <URL>
```

Get help:

```sh
dialogflow-fulfillment-tester --help
```

Tip: if you are on node and firebase functions, run your function locally using the firebase functions emulator

## Installing the UI

If you want the UI, clone this repo and put the `ui` folder near the executable.

Notice: when running Dialogflow Fulfillment Tester on a diffrent host/port, make sure to change it in the UI as well (`index.html`):

```js
let url = "http://localhost:8899" // <- Change the url, when running on a different host/port
```

Notice: the UI doesn't actually display Actions on Google components. I don't have time to do that, you can [donate](https://paypal.me/mishushakov) to make me reconsider it or implement it yourself and make a pull request to this repo

Tip: When inspecting using the UI, open the console to see the request/response body

## Making Requests

The request/response format of the Dialogflow Fulfillment Tester is equal to the Dialogflow Gateway request/response format, which is equal to the Dialogflow request/response format. Read the docs [here](https://github.com/mishushakov/dialogflow-gateway-docs/blob/master/api.md)

## Building from source

- Get [Go](https://golang.org/dl/)
- Build using `build.sh` script
- Ready!
3 changes: 3 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
GOOS=darwin go build -o ./bin/fulfillment-tester-darwin -ldflags="-s -w" ./main.go
GOARCH=amd64 GOOS=linux go build -o ./bin/fulfillment-tester-linux -ldflags="-s -w" ./main.go
GOOS=windows go build -o ./bin/fulfillment-tester-win -ldflags="-s -w" ./main.go
81 changes: 81 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package main

import (
"bytes"
"encoding/json"
"flag"
"io/ioutil"
"net/http"
)

// Declaring Variables
var (
Project string // Project ID
Fulfillment string // Fulfillment Host
Port string // Port to run the fulfillment-tester at
)

func proxy(res http.ResponseWriter, req *http.Request) {
// Set response Headers
res.Header().Set("Access-Control-Allow-Origin", "*")
res.Header().Set("Access-Control-Allow-Headers", "Content-Type, Cache-Control")
res.Header().Set("Access-Control-Allow-Methods", "*")

if req.Method == "POST" {
// Proxy request to Dialogflow Gateway (Session ID is always fulfillment-tester)
resp, _ := http.Post("https://"+Project+".gateway.dialogflow.cloud.ushakov.co/fulfillment-tester", "application/json", req.Body)
if resp.StatusCode != 200 {
res.WriteHeader(403)
}

// Read the response from Dialogflow Gateway
// Add session identifier to response
// Generate new JSON
resp_body, _ := ioutil.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(resp_body, &result)
result["session"] = "projects/" + Project + "/agent/sessions/fulfillment-tester"
data, _ := json.Marshal(result)

// Send the response to Fulfillment
fulfillment_resp, _ := http.Post(Fulfillment, "application/json", bytes.NewReader(data))

// Parse the fulfillment_messages from the Fulfillment response
// Overwrite queryResult on response (addr is the address of the queryResult field, that can be pointed to later)
// That's how Dialogflow actually responds with fulfillment option enabled (you don't have to be a Googler to tell that)
fulfillment_messages, _ := ioutil.ReadAll(fulfillment_resp.Body)
var addr = result["queryResult"]
json.Unmarshal(fulfillment_messages, &addr)

// Convert output back to JSON and send it to the client
output, _ := json.Marshal(result)
res.Write(output)
} else if req.Method == "OPTIONS" {
res.WriteHeader(200)
} else {
res.WriteHeader(404)
}
}

func main() {
// Parse flags, setup default flags and descriptions
flag.StringVar(&Project, "project", "dialogflow-web-v2", "Dialogflow Gateway Project ID")
flag.StringVar(&Fulfillment, "fulfillment", "https://us-central1-dialogflow-web-v2.cloudfunctions.net/dialogflowFirebaseFulfillment", "URL to fullfillment (remote or local)")
flag.StringVar(&Port, "port", "8899", "Port to run the fulfillment-tester at")
flag.Parse()

// Log some useful information to console
println("Dialogflow Fulfillment Tester is running 🚀")
println("Listening on: http://localhost:" + Port)
println("Web UI at: http://localhost:" + Port + "/ui" + "\n")
println("Connection 🔌")
println("Project ID: " + Project)
println("Fulfillment URL: " + Fulfillment)
println("\nHappy Testing!")

// Setup HTTP Server and Proxy (Handler)
// Setup the Web Server for the Web Client
http.HandleFunc("/", proxy)
http.Handle("/ui/", http.StripPrefix("/ui", http.FileServer(http.Dir("ui"))))
panic(http.ListenAndServe(":"+Port, nil))
}
11 changes: 11 additions & 0 deletions test.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
POST http://localhost:8899
Content-Type: application/json

{
"queryInput": {
"text": {
"text": "Webhook Demo",
"languageCode": "en"
}
}
}
1 change: 1 addition & 0 deletions ui/assets/card.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions ui/assets/send.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 4eba477

Please sign in to comment.