Skip to content

Commit 2a31091

Browse files
committed
Make tests for URL load check rule functions self contained
Several rules check whether URLs provided in project metadata load. Previously, the handling of various HTTP response status codes of these rule functions was tested by using the convenient httpstat.us site. Unfortunately the maintainers of that site shut it down months ago due to abuse. This caused the spurious failure of the unit tests. Although the httpstat.us maintainers state that they plan to eventually resume service, there hasn't been any indication of progress on that front. So it will be best to make the tests self contained, without any dependence on an external site. This is accomplished by creating a local HTTP server that responds with the intended status code. Unfortunately this does require the addition of code to the test in order to generate test data on the fly in order to reference the arbitrary port of the test server.
1 parent c142981 commit 2a31091

File tree

10 files changed

+590
-212
lines changed

10 files changed

+590
-212
lines changed

internal/rule/rulefunction/library_test.go

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,20 @@ package rulefunction
1818

1919
import (
2020
"fmt"
21+
"net/http"
2122
"os"
2223
"regexp"
24+
"strings"
2325
"testing"
2426
"time"
2527

2628
"github.com/arduino/arduino-lint/internal/project"
2729
"github.com/arduino/arduino-lint/internal/project/projectdata"
2830
"github.com/arduino/arduino-lint/internal/project/projecttype"
2931
"github.com/arduino/arduino-lint/internal/rule/ruleresult"
32+
"github.com/arduino/arduino-lint/internal/util/test"
3033
"github.com/arduino/go-paths-helper"
34+
"github.com/arduino/go-properties-orderedmap"
3135
"github.com/go-git/go-git/v5"
3236
"github.com/go-git/go-git/v5/plumbing/object"
3337
"github.com/stretchr/testify/assert"
@@ -780,11 +784,75 @@ func TestLibraryPropertiesUrlFieldDeadLink(t *testing.T) {
780784
{"Unable to load", "InvalidLibraryProperties", ruleresult.NotRun, ""},
781785
{"Not defined", "MissingFields", ruleresult.NotRun, ""},
782786
{"Bad URL", "BadURL", ruleresult.Fail, "^Head \"http://invalid/\": dial tcp: lookup invalid"},
783-
{"HTTP error 404", "URL404", ruleresult.Fail, "^404 Not Found$"},
784-
{"Good URL", "Recursive", ruleresult.Pass, ""},
785787
}
786788

787789
checkLibraryRuleFunction(LibraryPropertiesURLFieldDeadLink, testTables, t)
790+
791+
/*
792+
In order to avoid a dependency on an external site, a test HTTP server is used for the tests covering handling of
793+
various HTTP response status codes. For this reason, the following tests can't be performed via the
794+
checkLibraryRuleFunction function.
795+
*/
796+
statusTestTables := []struct {
797+
testName string
798+
serverStatus int
799+
expectedRuleResult ruleresult.Type
800+
expectedOutputQuery string
801+
}{
802+
{"HTTP error 404", http.StatusNotFound, ruleresult.Fail, "^404 Not Found$"},
803+
{"Good URL", http.StatusOK, ruleresult.Pass, ""},
804+
}
805+
806+
var propertiesMap = map[string]string{
807+
"name": "WebServer",
808+
"version": "1.0.0",
809+
"author": "Cristian Maglie <[email protected]>, Pippo Pluto <[email protected]>",
810+
"maintainer": "Cristian Maglie <[email protected]>",
811+
"sentence": "A library that makes coding a Webserver a breeze.",
812+
"paragraph": "Supports HTTP1.1 and you can do GET and POST.",
813+
"category": "Communication",
814+
"architectures": "avr",
815+
}
816+
817+
libraryProperties := properties.NewFromHashmap(propertiesMap)
818+
819+
for _, testTable := range statusTestTables {
820+
// Create an HTTP server that will return the desired status.
821+
server := test.StatusServer(testTable.serverStatus)
822+
defer server.Close()
823+
824+
libraryProperties.Set("url", server.URL)
825+
// AsSlice is the closest thing to a []byte output function provided by
826+
// `github.com/arduino/go-properties-orderedmap`.
827+
propertiesBytes := []byte(strings.Join(libraryProperties.AsSlice(), "\n"))
828+
829+
// Generate the test data library.
830+
sourcePath := librariesTestDataPath.Join("TestLibraryPropertiesUrlFieldDeadLink")
831+
tempPath, err := paths.MkTempDir("", "TestLibraryPropertiesUrlFieldDeadLink")
832+
defer tempPath.RemoveAll() // Clean up after the test.
833+
require.NoError(t, err)
834+
libraryPath := tempPath.Join("TestLibraryPropertiesUrlFieldDeadLink")
835+
err = sourcePath.CopyDirTo(libraryPath)
836+
require.NoError(t, err)
837+
err = libraryPath.Join("library.properties").WriteFile(propertiesBytes)
838+
require.NoError(t, err)
839+
840+
testProject := project.Type{
841+
Path: libraryPath,
842+
ProjectType: projecttype.Library,
843+
SuperprojectType: projecttype.Library,
844+
}
845+
projectdata.Initialize(testProject)
846+
847+
result, output := LibraryPropertiesURLFieldDeadLink()
848+
assert.Equal(t, testTable.expectedRuleResult, result, testTable.testName)
849+
expectedOutputRegexp := regexp.MustCompile(testTable.expectedOutputQuery)
850+
assert.True(
851+
t,
852+
expectedOutputRegexp.MatchString(output),
853+
fmt.Sprintf("%s (output: %s, assertion regex: %s)", testTable.testName, output, testTable.expectedOutputQuery),
854+
)
855+
}
788856
}
789857

790858
func TestLibraryPropertiesArchitecturesFieldMissing(t *testing.T) {

0 commit comments

Comments
 (0)