2021-02-25 18:02:43 +00:00
package main
import (
2023-01-24 16:34:52 +00:00
"flag"
2021-02-25 18:02:43 +00:00
"fmt"
"os"
2023-04-16 17:49:35 +00:00
"sort"
2021-02-25 18:02:43 +00:00
"strings"
"github.com/logrusorgru/aurora"
2021-11-25 15:09:20 +00:00
2021-11-04 21:31:41 +00:00
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
2023-03-17 16:31:28 +00:00
sliceutil "github.com/projectdiscovery/utils/slice"
2021-02-25 18:02:43 +00:00
)
var (
2021-12-14 16:13:53 +00:00
debug = os . Getenv ( "DEBUG" ) == "true"
githubAction = os . Getenv ( "GH_ACTION" ) == "true"
customTests = os . Getenv ( "TESTS" )
2021-07-30 09:59:12 +00:00
2021-12-14 16:13:53 +00:00
success = aurora . Green ( "[✓]" ) . String ( )
failed = aurora . Red ( "[✘]" ) . String ( )
2021-02-25 18:02:43 +00:00
2021-12-14 16:13:53 +00:00
protocolTests = map [ string ] map [ string ] testutils . TestCase {
2023-03-17 15:56:14 +00:00
"http" : httpTestcases ,
2023-04-16 17:49:35 +00:00
"interactsh" : interactshTestCases ,
2023-03-17 15:56:14 +00:00
"network" : networkTestcases ,
"dns" : dnsTestCases ,
"workflow" : workflowTestcases ,
"loader" : loaderTestcases ,
"websocket" : websocketTestCases ,
"headless" : headlessTestcases ,
"whois" : whoisTestCases ,
"ssl" : sslTestcases ,
"code" : codeTestcases ,
"templatesPath" : templatesPathTestCases ,
"templatesDir" : templatesDirTestCases ,
"file" : fileTestcases ,
"offlineHttp" : offlineHttpTestcases ,
"customConfigDir" : customConfigDirTestCases ,
"fuzzing" : fuzzingTestCases ,
2021-02-26 20:53:06 +00:00
}
2023-01-24 16:34:52 +00:00
// For debug purposes
2023-04-16 17:49:35 +00:00
runProtocol = ""
runTemplate = ""
extraArgs = [ ] string { }
interactshRetryCount = 3
2021-12-14 16:13:53 +00:00
)
2021-02-26 20:53:06 +00:00
2021-12-14 16:13:53 +00:00
func main ( ) {
2023-01-24 16:34:52 +00:00
flag . StringVar ( & runProtocol , "protocol" , "" , "run integration tests of given protocol" )
flag . StringVar ( & runTemplate , "template" , "" , "run integration test of given template" )
flag . Parse ( )
2023-02-01 11:53:28 +00:00
// allows passing extra args to nuclei
eargs := os . Getenv ( "DebugExtraArgs" )
if eargs != "" {
extraArgs = strings . Split ( eargs , " " )
testutils . ExtraDebugArgs = extraArgs
}
2023-01-24 16:34:52 +00:00
if runProtocol != "" {
debugTests ( )
os . Exit ( 1 )
}
2023-03-17 16:31:28 +00:00
customTestsList := normalizeSplit ( customTests )
failedTestTemplatePaths := runTests ( customTestsList )
2021-12-14 16:13:53 +00:00
if len ( failedTestTemplatePaths ) > 0 {
if githubAction {
debug = true
fmt . Println ( "::group::Failed integration tests in debug mode" )
_ = runTests ( failedTestTemplatePaths )
fmt . Println ( "::endgroup::" )
}
os . Exit ( 1 )
}
}
2023-04-16 17:49:35 +00:00
// execute a testcase with retry and consider best of N
// intended for flaky tests like interactsh
func executeWithRetry ( testCase testutils . TestCase , templatePath string , retryCount int ) ( string , error ) {
var err error
for i := 0 ; i < retryCount ; i ++ {
err = testCase . Execute ( templatePath )
if err == nil {
fmt . Printf ( "%s Test \"%s\" passed!\n" , success , templatePath )
return "" , nil
}
}
_ , _ = fmt . Fprintf ( os . Stderr , "%s Test \"%s\" failed after %v attempts : %s\n" , failed , templatePath , retryCount , err )
return templatePath , err
}
2023-01-24 16:34:52 +00:00
func debugTests ( ) {
2023-04-16 17:49:35 +00:00
keys := getMapKeys ( protocolTests [ runProtocol ] )
for _ , tpath := range keys {
testcase := protocolTests [ runProtocol ] [ tpath ]
2023-01-24 16:34:52 +00:00
if runTemplate != "" && ! strings . Contains ( tpath , runTemplate ) {
continue
}
2023-04-16 17:49:35 +00:00
if runProtocol == "interactsh" {
if _ , err := executeWithRetry ( testcase , tpath , interactshRetryCount ) ; err != nil {
fmt . Printf ( "\n%v" , err . Error ( ) )
}
} else {
if _ , err := execute ( testcase , tpath ) ; err != nil {
fmt . Printf ( "\n%v" , err . Error ( ) )
}
2023-01-24 16:34:52 +00:00
}
}
}
2023-03-17 16:31:28 +00:00
func runTests ( customTemplatePaths [ ] string ) [ ] string {
var failedTestTemplatePaths [ ] string
2021-12-14 16:13:53 +00:00
for proto , testCases := range protocolTests {
if len ( customTemplatePaths ) == 0 {
fmt . Printf ( "Running test cases for %q protocol\n" , aurora . Blue ( proto ) )
}
2023-04-16 17:49:35 +00:00
keys := getMapKeys ( testCases )
2021-12-14 16:13:53 +00:00
2023-04-16 17:49:35 +00:00
for _ , templatePath := range keys {
testCase := testCases [ templatePath ]
2023-03-17 16:31:28 +00:00
if len ( customTemplatePaths ) == 0 || sliceutil . Contains ( customTemplatePaths , templatePath ) {
2023-04-16 17:49:35 +00:00
var failedTemplatePath string
var err error
if proto == "interactsh" {
failedTemplatePath , err = executeWithRetry ( testCase , templatePath , interactshRetryCount )
} else {
failedTemplatePath , err = execute ( testCase , templatePath )
}
if err != nil {
2023-03-17 16:31:28 +00:00
failedTestTemplatePaths = append ( failedTestTemplatePaths , failedTemplatePath )
2021-02-26 20:53:06 +00:00
}
}
2021-02-25 18:02:43 +00:00
}
}
2021-12-14 16:13:53 +00:00
return failedTestTemplatePaths
}
2022-10-13 16:05:10 +00:00
func execute ( testCase testutils . TestCase , templatePath string ) ( string , error ) {
2021-12-14 16:13:53 +00:00
if err := testCase . Execute ( templatePath ) ; err != nil {
_ , _ = fmt . Fprintf ( os . Stderr , "%s Test \"%s\" failed: %s\n" , failed , templatePath , err )
2022-10-13 16:05:10 +00:00
return templatePath , err
2021-07-30 09:59:12 +00:00
}
2021-12-14 16:13:53 +00:00
fmt . Printf ( "%s Test \"%s\" passed!\n" , success , templatePath )
2022-10-13 16:05:10 +00:00
return "" , nil
2021-02-25 18:02:43 +00:00
}
2023-04-16 17:49:35 +00:00
func expectResultsCount ( results [ ] string , expectedNumbers ... int ) error {
match := sliceutil . Contains ( expectedNumbers , len ( results ) )
if ! match {
return fmt . Errorf ( "incorrect number of results: %d (actual) vs %v (expected) \nResults:\n\t%s\n" , len ( results ) , expectedNumbers , strings . Join ( results , "\n\t" ) )
2021-12-15 14:03:57 +00:00
}
return nil
2021-02-25 18:02:43 +00:00
}
2021-12-14 16:13:53 +00:00
2023-03-17 16:31:28 +00:00
func normalizeSplit ( str string ) [ ] string {
2023-04-04 02:09:52 +00:00
return strings . FieldsFunc ( str , func ( r rune ) bool {
return r == ','
} )
2021-12-14 16:13:53 +00:00
}
2023-04-16 17:49:35 +00:00
func getMapKeys [ T any ] ( testcases map [ string ] T ) [ ] string {
keys := make ( [ ] string , 0 , len ( testcases ) )
for k := range testcases {
keys = append ( keys , k )
}
sort . Strings ( keys )
return keys
}