Skip to content
Snippets Groups Projects
Commit 122a1fad authored by ale's avatar ale
Browse files

Fix a Scan() error, add tests

parent 3b10ee5f
Branches
No related tags found
No related merge requests found
......@@ -141,7 +141,8 @@ func (s *Server) findApps(ctx context.Context, queryName string, args ...interfa
for rows.Next() {
var app proto.App
var rowID int64
if err := rows.Scan(&rowID, &app.Site, &app.Shard, &app.Name, &app.Version, &app.SafeVersion, &app.State, &app.VulnInfo, &app.Timestamp); err != nil {
if err := rows.Scan(&rowID, &app.Site, &app.Shard, &app.Path, &app.Name, &app.Version, &app.SafeVersion, &app.State, &app.VulnInfo, &app.Timestamp); err != nil {
log.Printf("Scan error: %v", err)
continue
}
out = append(out, &app)
......@@ -168,6 +169,10 @@ func (s *Server) countApps(ctx context.Context, req *proto.CountAppsRequest) (*p
}
defer tx.Rollback() // nolint
if req.Limit == 0 {
req.Limit = 20
}
// This is just a query builder.
groupFields := []string{"state"}
if req.GroupByName {
......
package webappdb
import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
proto "git.autistici.org/ai3/tools/webappdb/proto"
"github.com/google/go-cmp/cmp"
)
var testApps = []*proto.App{
&proto.App{
Shard: "1",
Path: "/var/www/site1/wordpress",
Name: "Wordpress",
Version: "2.0",
SafeVersion: "3.5.1",
State: "vulnerable",
VulnInfo: "CVE-BLAH-BLAH",
Timestamp: time.Now(),
},
&proto.App{
Shard: "1",
Path: "/var/www/site1/wordpress-ok",
Name: "Wordpress",
Version: "3.5.1",
State: "ok",
Timestamp: time.Now(),
},
&proto.App{
Shard: "1",
Path: "/var/www/site2/ok",
Name: "Drupal",
Version: "1.0",
State: "ok",
Timestamp: time.Now(),
},
}
func startTestServer(t *testing.T, fixtures []*proto.App) (*httptest.Server, func()) {
// Initialize a temporary directory with database and a test
// homedir map.
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
// nolint: errcheck
ioutil.WriteFile(filepath.Join(dir, "homedir-map.json"), []byte(`{
"/var/www/site1": "site1",
"/var/www/site2": "site2"
}`), 0600)
database, err := OpenDB(filepath.Join(dir, "apps.db"))
if err != nil {
t.Fatalf("OpenDB: %v", err)
}
srv, err := New(database, filepath.Join(dir, "homedir-map.json"))
if err != nil {
t.Fatalf("New: %v", err)
}
httpSrv := httptest.NewServer(srv.Handler())
if len(fixtures) > 0 {
srv.insertApps(context.Background(), fixtures[0].Shard, fixtures) // nolint
}
return httpSrv, func() {
httpSrv.Close()
srv.Close()
database.Close()
os.RemoveAll(dir)
}
}
func makeRequest(t *testing.T, uri string, req, resp interface{}) {
data, err := json.Marshal(req)
if err != nil {
t.Fatalf("request encoding error: %v", err)
}
httpResp, err := http.Post(uri, "application/json", bytes.NewReader(data))
if err != nil {
t.Fatalf("http.Post(%s): %v", uri, err)
}
defer httpResp.Body.Close()
if httpResp.StatusCode != 200 {
t.Fatalf("http.Post(%s): HTTP error: %s", uri, httpResp.Status)
}
if resp != nil {
if err = json.NewDecoder(httpResp.Body).Decode(resp); err != nil {
t.Fatalf("http.Post(%s): response decode error: %v", uri, err)
}
}
}
func TestSubmission(t *testing.T) {
httpSrv, cleanup := startTestServer(t, nil)
defer cleanup()
// Load some data.
makeRequest(t, httpSrv.URL+"/api/submission", &proto.SubmissionRequest{
Shard: "1",
Entries: testApps,
}, nil)
// Query the data.
var findAppsResp proto.FindAppsByVersionResponse
makeRequest(t, httpSrv.URL+"/api/search/by_version", &proto.FindAppsByVersionRequest{
Name: "Wordpress",
Version: "2.0",
}, &findAppsResp)
if n := len(findAppsResp.Apps); n != 1 {
t.Fatalf("search/by_version response returned %d entries, expected %d", n, 1)
}
// If path -> site mapping works, results (having gone through
// the Submission interface) should have the Site attribute
// set to the expected value.
if site := findAppsResp.Apps[0].Site; site != "site1" {
t.Fatalf("site mapping failure: expected=site1, got=%s", site)
}
}
func TestFindAppsByVersion(t *testing.T) {
httpSrv, cleanup := startTestServer(t, testApps)
defer cleanup()
// Query a specific version.
var findAppsResp proto.FindAppsByVersionResponse
makeRequest(t, httpSrv.URL+"/api/search/by_version", &proto.FindAppsByVersionRequest{
Name: "Wordpress",
Version: "2.0",
}, &findAppsResp)
if n := len(findAppsResp.Apps); n != 1 {
t.Fatalf("search/by_version response returned %d entries, expected %d", n, 1)
}
// Query only the app name.
makeRequest(t, httpSrv.URL+"/api/search/by_version", &proto.FindAppsByVersionRequest{
Name: "Wordpress",
}, &findAppsResp)
if n := len(findAppsResp.Apps); n != 2 {
t.Fatalf("search/by_version response returned %d entries, expected %d", n, 2)
}
}
func TestCountApps(t *testing.T) {
httpSrv, cleanup := startTestServer(t, testApps)
defer cleanup()
var resp proto.CountAppsResponse
makeRequest(t, httpSrv.URL+"/api/count", &proto.CountAppsRequest{
GroupByName: true,
}, &resp)
expected := proto.CountAppsResponse{
Fields: []string{"state", "name"},
Results: []proto.CountResult{
{Keys: []string{"ok", "Drupal"}, Count: 1},
{Keys: []string{"ok", "Wordpress"}, Count: 1},
{Keys: []string{"vulnerable", "Wordpress"}, Count: 1},
},
}
if diffs := cmp.Diff(expected, resp); diffs != "" {
t.Fatalf("/api/count(group_by_name=true) got unexpected results: %s", diffs)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment