feat(GODT-3121): added options to kb-tester CLI tool.

This commit is contained in:
Xavier Michelon
2023-12-08 09:59:04 +01:00
parent 789c1cc816
commit 416f696863
4 changed files with 136 additions and 28 deletions

View File

@ -4,8 +4,7 @@
"url": "https://proton.me/support/automatically-start-bridge", "url": "https://proton.me/support/automatically-start-bridge",
"title": "Automatically start Bridge", "title": "Automatically start Bridge",
"keywords": [ "keywords": [
"start", "automatic",
"automatically",
"login", "login",
"start", "start",
"boot" "boot"
@ -53,7 +52,8 @@
"title": "Proton Mail Bridge connection issues with Thunderbird, Outlook, and Apple Mail", "title": "Proton Mail Bridge connection issues with Thunderbird, Outlook, and Apple Mail",
"keywords": [ "keywords": [
"connect", "connect",
"error", "SSL",
"STARTTLS",
"client", "client",
"program", "program",
"Outlook", "Outlook",
@ -68,7 +68,8 @@
"keywords": [ "keywords": [
"pgp", "pgp",
"gpg", "gpg",
"encrypt" "encrypt",
"crypto"
] ]
}, },
{ {
@ -205,7 +206,6 @@
"Outlook", "Outlook",
"configure", "configure",
"setup", "setup",
"program",
"application", "application",
"setup", "setup",
"IMAP", "IMAP",

View File

@ -52,14 +52,20 @@ func GetArticleList() (ArticleList, error) {
return articles, err return articles, err
} }
// GetSuggestions return a list of up to 3 suggestions for KB articles matching the given user input. // GetSuggestions returns a list of up to 3 suggestions for the built-in list of KB articles matching the given user input.
func GetSuggestions(userInput string) (ArticleList, error) { func GetSuggestions(userInput string) (ArticleList, error) {
userInput = strings.ToUpper(userInput)
articles, err := GetArticleList() articles, err := GetArticleList()
if err != nil { if err != nil {
return ArticleList{}, err return ArticleList{}, err
} }
return GetSuggestionsFromArticleList(userInput, articles)
}
// GetSuggestionsFromArticleList returns a list of up to 3 suggestions for the given list of KB articles matching the given user input.
func GetSuggestionsFromArticleList(userInput string, articles ArticleList) (ArticleList, error) {
userInput = strings.ToUpper(userInput)
for _, article := range articles { for _, article := range articles {
for _, keyword := range article.Keywords { for _, keyword := range article.Keywords {
if strings.Contains(userInput, strings.ToUpper(keyword)) { if strings.Contains(userInput, strings.ToUpper(keyword)) {
@ -78,7 +84,7 @@ func GetSuggestions(userInput string) (ArticleList, error) {
return articles, nil return articles, nil
} }
// GetArticleIndex retrieve the index of an article from its url. if the article is not found, ErrArticleNotFound is returned. // GetArticleIndex retrieves the index of an article from its url. if the article is not found, ErrArticleNotFound is returned.
func GetArticleIndex(url string) (uint64, error) { func GetArticleIndex(url string) (uint64, error) {
articles, err := GetArticleList() articles, err := GetArticleList()
if err != nil { if err != nil {

View File

@ -18,7 +18,6 @@
package kb package kb
import ( import (
"fmt"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -42,16 +41,39 @@ func Test_ArticleList(t *testing.T) {
func Test_GetSuggestions(t *testing.T) { func Test_GetSuggestions(t *testing.T) {
suggestions, err := GetSuggestions("Thunderbird is not working, error during password") suggestions, err := GetSuggestions("Thunderbird is not working, error during password")
require.NoError(t, err) require.NoError(t, err)
require.True(t, len(suggestions) <= 3) count := len(suggestions)
for _, article := range suggestions { require.True(t, (count > 0) && (count <= 3))
fmt.Printf("Score: %v - %#v\n", article.Score, article.Title)
}
suggestions, err = GetSuggestions("Supercalifragilisticexpialidocious Sesquipedalian Worcestershire") suggestions, err = GetSuggestions("Supercalifragilisticexpialidocious Sesquipedalian Worcestershire")
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, suggestions) require.Empty(t, suggestions)
} }
func Test_GetSuggestionsFromArticleList(t *testing.T) {
articleList := ArticleList{}
suggestions, err := GetSuggestionsFromArticleList("Thunderbird", articleList)
require.NoError(t, err)
require.Empty(t, suggestions)
articleList = ArticleList{
&Article{
Index: 0,
URL: "https://proton.me",
Title: "Proton home page",
Keywords: []string{"proton"},
},
&Article{
Index: 1,
URL: "https://mozilla.org",
Title: "Mozilla home page",
Keywords: []string{"mozilla"},
},
}
suggestions, err = GetSuggestionsFromArticleList("PRoToN", articleList)
require.NoError(t, err)
require.Len(t, suggestions, 1)
require.Equal(t, suggestions[0].URL, "https://proton.me")
}
func Test_GetArticleIndex(t *testing.T) { func Test_GetArticleIndex(t *testing.T) {
index1, err := GetArticleIndex("https://proton.me/support/bridge-for-linux") index1, err := GetArticleIndex("https://proton.me/support/bridge-for-linux")
require.NoError(t, err) require.NoError(t, err)

View File

@ -18,40 +18,120 @@
package main package main
import ( import (
"encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"log"
"os" "os"
"path/filepath"
"github.com/ProtonMail/proton-bridge/v3/internal/kb" "github.com/ProtonMail/proton-bridge/v3/internal/kb"
"github.com/urfave/cli/v2"
) )
func checkErrors(err error) { const flagArticles = "articles"
if err != nil { const flagInput = "input"
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1) func main() {
app := &cli.App{
Name: "kb-suggester",
Usage: "test bridge KB article suggester",
HideHelpCommand: true,
ArgsUsage: "",
Flags: []cli.Flag{
&cli.StringFlag{
Name: flagArticles,
Aliases: []string{"a"},
Usage: "use `articles.json` as the JSON article list",
TakesFile: true,
},
&cli.StringFlag{
Name: flagInput,
Aliases: []string{"i"},
Usage: "read user input from the `userInput` file",
TakesFile: true,
},
},
Action: run,
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
} }
} }
func main() { func getUserInput(ctx *cli.Context) (string, error) {
fi, err := os.Stdin.Stat() inputFile := ctx.String(flagInput)
checkErrors(err) var bytes []byte
var err error
if (fi.Mode() & os.ModeNamedPipe) == 0 { if len(inputFile) == 0 {
fmt.Println("Type your input, Ctrl+D to finish: ") var fi os.FileInfo
if fi, err = os.Stdin.Stat(); err != nil {
return "", err
}
if (fi.Mode() & os.ModeNamedPipe) == 0 {
fmt.Println("Type your input, Ctrl+D to finish: ")
}
bytes, err = io.ReadAll(os.Stdin)
} else {
bytes, err = os.ReadFile(filepath.Clean(inputFile))
} }
bytes, err := io.ReadAll(os.Stdin) if err != nil {
checkErrors(err) return "", err
}
suggestions, err := kb.GetSuggestions(string(bytes)) return string(bytes), nil
checkErrors(err) }
func getArticleList(ctx *cli.Context) (kb.ArticleList, error) {
articleFile := ctx.String(flagArticles)
if len(articleFile) == 0 {
return kb.GetArticleList()
}
bytes, err := os.ReadFile(filepath.Clean(articleFile))
if err != nil {
return nil, err
}
var result kb.ArticleList
err = json.Unmarshal(bytes, &result)
return result, err
}
func run(ctx *cli.Context) error {
if ctx.Args().Len() > 0 {
_ = cli.ShowAppHelp(ctx)
return errors.New("command accept no argument")
}
articles, err := getArticleList(ctx)
if err != nil {
return err
}
userInput, err := getUserInput(ctx)
if err != nil {
return err
}
suggestions, err := kb.GetSuggestionsFromArticleList(userInput, articles)
if err != nil {
return err
}
if len(suggestions) == 0 { if len(suggestions) == 0 {
fmt.Println("No suggestions found") fmt.Println("No suggestions found")
return return nil
} }
for _, suggestion := range suggestions { for _, suggestion := range suggestions {
fmt.Printf("Score %v: %v (%v)\n", suggestion.Score, suggestion.Title, suggestion.URL) fmt.Printf("Score %v: %v (%v)\n", suggestion.Score, suggestion.Title, suggestion.URL)
} }
return nil
} }