Skip to content

Commit 47c32ad

Browse files
authored
tests(deepsource): add tests for analyzer API (#130)
* tests(deepsource): add tests for analyzer API Signed-off-by: burntcarrot <aadhav.n1@gmail.com> * fix(deepsource): fix equality checks and goroutine termination Signed-off-by: burntcarrot <aadhav.n1@gmail.com> * refactor(tests): move tests to a new directory Signed-off-by: burntcarrot <aadhav.n1@gmail.com>
1 parent 9616e45 commit 47c32ad

6 files changed

Lines changed: 134 additions & 0 deletions

File tree

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ build_local:
77
test:
88
CGO_ENABLED=0 go test -v ./command/report/tests/... -run TestReportKeyValueWorkflow -count=1
99
CGO_ENABLED=0 go test -v ./command/report/tests/... -run TestReportKeyValueFileWorkflow -count=1
10+
echo "\n====TESTING DEEPSOURCE PACKAGE====\n"
11+
CGO_ENABLED=0 go test -v ./deepsource/tests/...
1012
echo "\n====TESTING CONFIG VALIDATOR PACKAGE====\n"
1113
go test -v ./configvalidator/... -count=1
1214
echo "\n====CALCULATING TEST COVERAGE FOR ENTIRE PACKAGE====\n"
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package tests
2+
3+
import (
4+
"context"
5+
"io/ioutil"
6+
"log"
7+
"net/http"
8+
"reflect"
9+
"testing"
10+
11+
analyzers "github.com/deepsourcelabs/cli/deepsource/analyzers/queries"
12+
"github.com/deepsourcelabs/graphql"
13+
)
14+
15+
// mock client
16+
type Client struct {
17+
gql *graphql.Client
18+
token string
19+
}
20+
21+
// Returns a GraphQL client which can be used to interact with the GQL APIs
22+
func (c Client) GQL() *graphql.Client {
23+
return c.gql
24+
}
25+
26+
// Returns the token which is required for authentication and thus, interacting with the APIs
27+
func (c Client) GetToken() string {
28+
return c.token
29+
}
30+
31+
func TestAnalyzers(t *testing.T) {
32+
t.Run("valid GraphQL request", func(t *testing.T) {
33+
// create client
34+
gql := graphql.NewClient("http://localhost:8081/analyzer")
35+
c := Client{gql: gql, token: "secret"}
36+
37+
// perform request
38+
req := analyzers.AnalyzersRequest{}
39+
ctx := context.Background()
40+
_, err := req.Do(ctx, c)
41+
if err != nil {
42+
t.Error(err.Error())
43+
}
44+
})
45+
}
46+
47+
// a mock GraphQL handler for testing
48+
func mockAnalyzer(w http.ResponseWriter, r *http.Request) {
49+
req, _ := ioutil.ReadAll(r.Body)
50+
51+
// Read test graphql request body artifact file
52+
requestBodyData, err := ioutil.ReadFile("./testdata/analyzer/request_body.txt")
53+
if err != nil {
54+
log.Println(err)
55+
return
56+
}
57+
58+
// Read test graphql success response body artifact file
59+
successResponseBodyData, err := ioutil.ReadFile("./testdata/analyzer/success_response_body.json")
60+
if err != nil {
61+
log.Println(err)
62+
return
63+
}
64+
65+
// Read test graphql error response body artifact file
66+
errorResponseBodyData, err := ioutil.ReadFile("./testdata/analyzer/error_response_body.json")
67+
if err != nil {
68+
log.Println(err)
69+
return
70+
}
71+
72+
w.WriteHeader(http.StatusOK)
73+
w.Header().Set("Content-Type", "application/json")
74+
75+
if reflect.DeepEqual(requestBodyData, req) {
76+
w.Write([]byte(successResponseBodyData))
77+
} else {
78+
w.Write([]byte(errorResponseBodyData))
79+
}
80+
}

deepsource/tests/init_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package tests
2+
3+
import (
4+
"log"
5+
"net/http"
6+
"os"
7+
"testing"
8+
)
9+
10+
var srv *http.Server
11+
12+
func TestMain(m *testing.M) {
13+
log.SetFlags(log.LstdFlags | log.Lshortfile)
14+
startMockAPIServer()
15+
16+
code := m.Run()
17+
18+
srv.Close()
19+
os.Exit(code)
20+
}
21+
22+
func startMockAPIServer() {
23+
// Start GraphQL server for test
24+
srv = &http.Server{
25+
Addr: ":8081",
26+
}
27+
28+
http.HandleFunc("/analyzer", mockAnalyzer)
29+
30+
go func() {
31+
err := srv.ListenAndServe()
32+
if err != nil {
33+
panic("Error starting HTTP mock server")
34+
}
35+
}()
36+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"message": "Something went wrong. We are investigating this. Kindly contact support@deepsource.io if the problem persists.",
3+
"documentation_url": "https://deepsource.io/docs/"
4+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
analyzers {
3+
edges {
4+
node {
5+
name
6+
shortcode
7+
metaSchema
8+
}
9+
}
10+
}
11+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"data":{"analyzers":{"edges":[{"node":{"name":"Scala","shortcode":"scala","metaSchema":"{\"type\": \"object\", \"properties\": {\"major_version\": {\"enum\": [\"2\", \"3\"], \"type\": \"string\", \"title\": \"Scala major version\", \"description\": \"Specifies the Scala version the codebase is in.\"}}}"}},{"node":{"name":"Java","shortcode":"java","metaSchema":"{\"type\": \"object\", \"properties\": {\"legacy\": {\"type\": \"boolean\", \"title\": \"Use DeepSource Legacy mode\", \"description\": \"Selecting this option may result in more issues being detected, but will also greatly increase analysis time and may cause timeouts. Use at your own risk.\"}, \"java_version\": {\"enum\": [\"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\"], \"type\": \"string\", \"title\": \"Java Runtime version\", \"description\": \"The version of the Java runtime to use. OpenJDK versions 8 to 15 are supported.\"}, \"runtime_version\": {\"enum\": [\"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\"], \"type\": \"string\", \"title\": \"Java Runtime version\", \"default\": \"11\", \"description\": \"The version of the Java runtime to use. OpenJDK versions 8 to 15 are supported.\"}}, \"optional_required\": [\"runtime_version\"]}"}},{"node":{"name":"Ansible","shortcode":"ansible","metaSchema":"{}"}},{"node":{"name":"C#","shortcode":"csharp","metaSchema":"{}"}},{"node":{"name":"JavaScript","shortcode":"javascript","metaSchema":"{\"type\": \"object\", \"required\": [], \"properties\": {\"dialect\": {\"enum\": [\"typescript\", \"flow\"], \"type\": \"string\", \"title\": \"Dialect of JavaScript\", \"labels\": {\"flow\": \"Flow\", \"typescript\": \"TypeScript\"}, \"description\": \"The dialect of Javascript used in the Project. Currently supports TypeScript and Flow.\"}, \"plugins\": {\"type\": \"array\", \"items\": {\"enum\": [\"react\", \"vue\", \"ember\", \"meteor\", \"angularjs\", \"angular\"]}, \"title\": \"Frameworks\", \"labels\": {\"vue\": \"Vue\", \"ember\": \"Ember\", \"react\": \"React\", \"meteor\": \"Meteor\", \"angular\": \"Angular\", \"angularjs\": \"AngularJS\"}, \"description\": \"The frameworks used in the Project. Currently supports React, Vue, Ember, Meteor, AngularJS and Angular\"}, \"environment\": {\"type\": \"array\", \"items\": {\"enum\": [\"nodejs\", \"browser\", \"jest\", \"mocha\", \"jasmine\", \"jquery\", \"mongo\", \"cypress\"]}, \"title\": \"Runtime environments\", \"labels\": {\"jest\": \"Jest\", \"mocha\": \"Mocha\", \"mongo\": \"Mongo\", \"jquery\": \"Jquery\", \"nodejs\": \"Node.js\", \"browser\": \"Browser\", \"cypress\": \"Cypress\", \"jasmine\": \"Jasmine\"}, \"description\": \"Define the environments that the application runs in. Helps the analyzer recognize runtime-specific names, like `it`, `console` and `window`. Setting this reduces false-positives.\", \"additionalProperties\": false}, \"style_guide\": {\"enum\": [\"airbnb\", \"google\", \"standard\"], \"type\": \"string\", \"title\": \"Preferred style guide\", \"labels\": {\"airbnb\": \"Airbnb\", \"google\": \"Google\", \"standard\": \"Standard\"}, \"description\": \"The preferred style guide to be used in the project. Currently supports Airbnb,Google and Standard.\", \"additionalProperties\": false}, \"ecma_version\": {\"enum\": [\"3\", \"5\", \"6\", \"2016\", \"2017\", \"2018\", \"2019\", \"2020\"], \"type\": \"string\", \"title\": \"ECMAScript(ES) Version\", \"labels\": {\"3\": \"ES3\", \"5\": \"ES5\", \"6\": \"ES6\", \"2016\": \"ES2016\", \"2017\": \"ES2017\", \"2018\": \"ES2018\", \"2019\": \"ES2019\", \"2020\": \"ES2020\"}, \"default\": \"2020\", \"description\": \"The ECMAScript(ES) version that the project follows.\", \"additionalProperties\": false}, \"module_system\": {\"enum\": [\"commonjs\", \"es-modules\", \"amd\"], \"type\": \"string\", \"title\": \"Module system\", \"labels\": {\"amd\": \"AMD\", \"commonjs\": \"CommonJS\", \"es-modules\": \"ES modules\"}, \"default\": \"commonjs\", \"description\": \"The type of modules used in the project. CommonJS(require/exports) or ESModules(import/export) or AMD(RequireJS)\", \"additionalProperties\": false}, \"skip_doc_coverage\": {\"type\": \"array\", \"items\": {\"enum\": [\"function-declaration\", \"function-expression\", \"arrow-function-expression\", \"class-declaration\", \"class-expression\", \"method-definition\"]}, \"title\": \"Skip documentation coverage\", \"labels\": {\"class-expression\": \"Class expression\", \"class-declaration\": \"Class declaration\", \"method-definition\": \"Method definition\", \"function-expression\": \"Function expression\", \"function-declaration\": \"Function declaration\", \"arrow-function-expression\": \"Arrow function expression\"}, \"description\": \"The nodes to skip when reporting documentation issues and coverage metric\", \"additionalProperties\": false}, \"dependency_file_paths\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}, \"title\": \"Dependency File Paths\", \"description\": \"These are the directories where package.json file is present. The list is needed to help us analyze the code in a better way and also improve the dependency calculation.\"}}, \"optional_required\": [\"plugins\"], \"additionalProperties\": false}"}},{"node":{"name":"Go","shortcode":"go","metaSchema":"{\"type\": \"object\", \"required\": [], \"properties\": {\"build_tags\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}, \"title\": \"Build tags\", \"description\": \"Build tags that will be used to build the packages. This prevents compilation-related issues (due to inclusion/exclusion of files) from being raised.\", \"additionalProperties\": false}, \"cgo_enabled\": {\"type\": \"boolean\", \"title\": \"Run CGo code\", \"default\": true, \"description\": \"If your code depends on CGo code, and would result in compilation error without that, set this to true. If your CGo code relies on packages installed in the OS, set it to false.\"}, \"import_path\": {\"type\": \"string\", \"title\": \"Import path\", \"description\": \"This is a single string, specifying the import path of the project.\"}, \"import_root\": {\"type\": \"string\", \"title\": \"Import root\", \"default\": [\"<%= vcs_host %>/<%= login %>/<%= name %>\"], \"description\": \"The source code will be placed in $GOPATH/src/{import_root}.\"}, \"import_paths\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}, \"title\": \"Import paths\", \"description\": \"This is an array of import paths in the repository. Each Go project in the repository should have its own import path.\"}, \"skip_doc_coverage\": {\"type\": \"array\", \"items\": {\"enum\": [\"file\"], \"type\": \"string\"}, \"title\": \"Skip in doc coverage\", \"description\": \"Types of objects that should be skipped while calculating documentation coverage.\", \"additionalProperties\": false}, \"dependencies_vendored\": {\"type\": \"boolean\", \"title\": \"Are dependencies vendored?\", \"labels\": {\"true\": \"Yes\", \"false\": \"No\"}, \"description\": \"If true, instructs the analyzer not to install dependencies, since they are already available in the `vendor/` directory of the repository\"}}, \"optional_required\": [\"import_root\", \"dependencies_vendored\"], \"additionalProperties\": false}"}},{"node":{"name":"PHP","shortcode":"php","metaSchema":"{\"type\": \"object\", \"required\": [], \"properties\": {\"bootstrap_files\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}, \"title\": \"Bootstrap files\", \"description\": \"List of files that your project is using to define global constants, custom autoloader, class aliases, etc. This will help reduce the false-positives. Note that these files will be executed by the analyzer before analysis is started.\"}, \"skip_doc_coverage\": {\"type\": \"array\", \"items\": {\"enum\": [\"class\", \"magic\", \"nonpublic\"], \"type\": \"string\"}, \"title\": \"Skip in doc coverage\", \"description\": \"Types of elements that should be skipped while calculating documentation coverage.\", \"additionalProperties\": false}}, \"optional_required\": [\"bootstrap_files\"], \"additionalProperties\": false}"}},{"node":{"name":"Python","shortcode":"python","metaSchema":"{\"type\": \"object\", \"properties\": {\"type_checker\": {\"enum\": [\"mypy\"], \"type\": \"string\", \"title\": \"Type checker\", \"description\": \"If you're using type annotations in your code, enable type checking with one of the checkers available.\"}, \"max_line_length\": {\"type\": \"integer\", \"title\": \"Maximum line length\", \"default\": 100, \"minimum\": 79, \"description\": \"Customize this according to your project's conventions.\"}, \"runtime_version\": {\"enum\": [\"3.x.x\", \"2.x.x\"], \"type\": \"string\", \"title\": \"Runtime version\", \"default\": \"3.x.x\", \"description\": \"Set it to the least version of Python that your code runs on.\"}, \"skip_doc_coverage\": {\"type\": \"array\", \"items\": {\"enum\": [\"magic\", \"init\", \"class\", \"module\", \"nonpublic\"], \"type\": \"string\"}, \"title\": \"Skip in doc coverage\", \"description\": \"Types of objects that should be skipped while calculating documentation coverage.\", \"additionalProperties\": false}, \"additional_builtins\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}, \"title\": \"Additional builtins\", \"description\": \"Additional names supposed to be defined in builtins\"}}, \"optional_required\": [\"runtime_version\"], \"additionalProperties\": false}"}},{"node":{"name":"Shell","shortcode":"shell","metaSchema":"{\"type\": \"object\", \"properties\": {\"dialect\": {\"enum\": [\"sh\", \"bash\", \"dash\", \"ksh\"], \"type\": \"string\", \"title\": \"Bourne shell dialect\", \"default\": \"Deduce the shell from the file's shell directive or the shebang.\", \"description\": \"Specify Bourne shell dialect. Valid values are `sh`, `bash`, `dash` and `ksh`.\"}}, \"optional_required\": [], \"additionalProperties\": false}"}},{"node":{"name":"Docker","shortcode":"docker","metaSchema":"{\"type\": \"object\", \"properties\": {\"dockerfile_paths\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}, \"title\": \"Custom Dockerfile paths\", \"description\": \"Full path of all custom Dockerfiles used. The Dockerfile in the repository's root is analyzed by default.\", \"placeholder\": \"src/Dockerfile\\nDockerfile.production\"}, \"trusted_registries\": {\"type\": \"array\", \"items\": {\"type\": \"string\", \"title\": \"Trusted registries\", \"description\": \"List of trusted registries from where images are pulled in Dockerfiles.\"}}}, \"optional_required\": [\"dockerfile_paths\"], \"additionalProperties\": false}"}},{"node":{"name":"Rust","shortcode":"rust","metaSchema":"{\"type\": \"object\", \"properties\": {\"msrv\": {\"type\": \"string\", \"title\": \"Minimum supported Rust version\", \"default\": \"1.30.0\", \"description\": \"The minimum Rust version that your project builds against\"}}, \"optional_required\": [\"msrv\"], \"additionalProperties\": false}"}},{"node":{"name":"Ruby","shortcode":"ruby","metaSchema":"{}"}},{"node":{"name":"Secrets","shortcode":"secrets","metaSchema":"{}"}},{"node":{"name":"SQL","shortcode":"sql","metaSchema":"{\"type\": \"object\", \"properties\": {\"comma_style\": {\"enum\": [\"trailing\", \"leading\"], \"type\": \"string\", \"title\": \"Comma style\", \"default\": \"trailing\", \"description\": \"Comma style to enforce.\"}, \"indent_unit\": {\"enum\": [\"space\", \"tab\"], \"type\": \"string\", \"title\": \"Indent unit\", \"default\": \"space\", \"description\": \"Whether to use tabs or spaces to add new indents.\"}, \"allow_scalar\": {\"type\": \"bool\", \"title\": \"Allow scalar\", \"default\": true, \"description\": \"If True then this rule will not fail if there is only one element in the select clause e.g. SELECT 1 + 2 FROM blah. It will still fail if there are multiple columns.\"}, \"tab_space_size\": {\"type\": \"integer\", \"title\": \"Tab space size\", \"default\": 4, \"description\": \"The number of spaces to consider equal to one tab. Defaults to 4.\"}, \"max_line_length\": {\"type\": \"integer\", \"title\": \"Maximum line length\", \"default\": 80, \"description\": \"Customize this according to your project's conventions.\"}, \"capitalisation_policy\": {\"enum\": [\"consistent\", \"upper\", \"lower\", \"capitalise\"], \"type\": \"string\", \"title\": \"Capitalisation policy\", \"default\": \"consistent\", \"description\": \"The capitalisation policy to enforce.\"}, \"single_table_references\": {\"enum\": [\"consistent\", \"qualified\", \"unqualified\"], \"type\": \"string\", \"title\": \"Single table references\", \"default\": \"consistent\", \"description\": \"The capitalisation policy to enforce.\"}}, \"optional_required\": [], \"additionalProperties\": false}"}},{"node":{"name":"Test coverage","shortcode":"test-coverage","metaSchema":"{}"}},{"node":{"name":"Terraform","shortcode":"terraform","metaSchema":"{\"type\": \"object\", \"properties\": {}, \"additionalProperties\": false}"}}]}}}

0 commit comments

Comments
 (0)