2015-01-28 07:27:46 +00:00
package notifications
import (
2016-07-09 19:59:05 +00:00
"crypto/tls"
2015-01-28 07:27:46 +00:00
"encoding/json"
"fmt"
"mime"
Fix unit test
If running test behide a proxy, we may get the error code
403 Forbidden which will fail line 135 for the last testcase.
Detail:
```
metrics not as expected: notifications.EndpointMetrics{Pending:0,
Events:0, Successes:4, Failures:0, Errors:0,
Statuses:map[string]int{"307 Temporary Redirect":0, "400 Bad Request":0,
"403 Forbidden":0, "200 OK":4}} !=
notifications.EndpointMetrics{Pending:0, Events:0, Successes:4,
Failures:0, Errors:0, Statuses:map[string]int{"400 Bad Request":0, "200
OK":4, "307 Temporary Redirect":0}}
```
Immediate close will fix that
Signed-off-by: Hu Keping <hukeping@huawei.com>
Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2017-01-10 01:10:49 +00:00
"net"
2015-01-28 07:27:46 +00:00
"net/http"
"net/http/httptest"
"reflect"
"strconv"
2020-02-23 01:27:55 +00:00
"strings"
2015-01-28 07:27:46 +00:00
"testing"
2015-03-05 04:57:14 +00:00
2023-05-09 11:18:47 +00:00
"github.com/distribution/distribution/v3/manifest/schema1" //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
2018-03-14 00:08:11 +00:00
events "github.com/docker/go-events"
2015-01-28 07:27:46 +00:00
)
// TestHTTPSink mocks out an http endpoint and notifies it under a couple of
// conditions, ensuring correct behavior.
func TestHTTPSink ( t * testing . T ) {
2016-07-09 19:59:05 +00:00
serverHandler := http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2015-01-28 07:27:46 +00:00
defer r . Body . Close ( )
2022-11-02 22:31:23 +00:00
if r . Method != http . MethodPost {
2015-01-28 07:27:46 +00:00
w . WriteHeader ( http . StatusMethodNotAllowed )
t . Fatalf ( "unexpected request method: %v" , r . Method )
return
}
// Extract the content type and make sure it matches
contentType := r . Header . Get ( "Content-Type" )
mediaType , _ , err := mime . ParseMediaType ( contentType )
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
t . Fatalf ( "error parsing media type: %v, contenttype=%q" , err , contentType )
return
}
if mediaType != EventsMediaType {
w . WriteHeader ( http . StatusUnsupportedMediaType )
t . Fatalf ( "incorrect media type: %q != %q" , mediaType , EventsMediaType )
return
}
var envelope Envelope
dec := json . NewDecoder ( r . Body )
if err := dec . Decode ( & envelope ) ; err != nil {
w . WriteHeader ( http . StatusBadRequest )
t . Fatalf ( "error decoding request body: %v" , err )
return
}
// Let caller choose the status
status , err := strconv . Atoi ( r . FormValue ( "status" ) )
if err != nil {
t . Logf ( "error parsing status: %v" , err )
// May just be empty, set status to 200
status = http . StatusOK
}
w . WriteHeader ( status )
2016-07-09 19:59:05 +00:00
} )
server := httptest . NewTLSServer ( serverHandler )
2015-01-28 07:27:46 +00:00
2018-10-11 13:39:02 +00:00
metrics := newSafeMetrics ( "" )
2016-07-09 19:59:05 +00:00
sink := newHTTPSink ( server . URL , 0 , nil , nil ,
2015-01-28 07:27:46 +00:00
& endpointMetricsHTTPStatusListener { safeMetrics : metrics } )
2016-07-09 19:59:05 +00:00
// first make sure that the default transport gives x509 untrusted cert error
2018-03-14 00:08:11 +00:00
event := Event { }
err := sink . Write ( event )
2017-05-15 15:34:14 +00:00
if ! strings . Contains ( err . Error ( ) , "x509" ) && ! strings . Contains ( err . Error ( ) , "unknown ca" ) {
2016-07-09 19:59:05 +00:00
t . Fatal ( "TLS server with default transport should give unknown CA error" )
}
if err := sink . Close ( ) ; err != nil {
t . Fatalf ( "unexpected error closing http sink: %v" , err )
}
// make sure that passing in the transport no longer gives this error
tr := & http . Transport {
TLSClientConfig : & tls . Config { InsecureSkipVerify : true } ,
}
sink = newHTTPSink ( server . URL , 0 , nil , tr ,
& endpointMetricsHTTPStatusListener { safeMetrics : metrics } )
2018-03-14 00:08:11 +00:00
err = sink . Write ( event )
2016-07-09 19:59:05 +00:00
if err != nil {
2018-03-14 00:08:11 +00:00
t . Fatalf ( "unexpected error writing event: %v" , err )
2016-07-09 19:59:05 +00:00
}
// reset server to standard http server and sink to a basic sink
2018-03-14 00:08:11 +00:00
metrics = newSafeMetrics ( "" )
2016-07-09 19:59:05 +00:00
server = httptest . NewServer ( serverHandler )
sink = newHTTPSink ( server . URL , 0 , nil , nil ,
& endpointMetricsHTTPStatusListener { safeMetrics : metrics } )
2015-01-28 07:27:46 +00:00
var expectedMetrics EndpointMetrics
expectedMetrics . Statuses = make ( map [ string ] int )
Fix unit test
If running test behide a proxy, we may get the error code
403 Forbidden which will fail line 135 for the last testcase.
Detail:
```
metrics not as expected: notifications.EndpointMetrics{Pending:0,
Events:0, Successes:4, Failures:0, Errors:0,
Statuses:map[string]int{"307 Temporary Redirect":0, "400 Bad Request":0,
"403 Forbidden":0, "200 OK":4}} !=
notifications.EndpointMetrics{Pending:0, Events:0, Successes:4,
Failures:0, Errors:0, Statuses:map[string]int{"400 Bad Request":0, "200
OK":4, "307 Temporary Redirect":0}}
```
Immediate close will fix that
Signed-off-by: Hu Keping <hukeping@huawei.com>
Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2017-01-10 01:10:49 +00:00
closeL , err := net . Listen ( "tcp" , "localhost:0" )
if err != nil {
t . Fatalf ( "unexpected error creating listener: %v" , err )
}
defer closeL . Close ( )
go func ( ) {
for {
c , err := closeL . Accept ( )
if err != nil {
return
}
c . Close ( )
}
} ( )
2015-01-28 07:27:46 +00:00
for _ , tc := range [ ] struct {
2018-03-14 00:08:11 +00:00
event events . Event // events to send
2015-01-28 07:27:46 +00:00
url string
2018-03-14 00:08:11 +00:00
isFailure bool // true if there should be a failure.
isError bool // true if the request returns an error
2015-01-28 07:27:46 +00:00
statusCode int // if not set, no status code should be incremented.
} {
{
statusCode : http . StatusOK ,
2023-05-09 11:18:47 +00:00
event : createTestEvent ( "push" , "library/test" , schema1 . MediaTypeSignedManifest ) , //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
2015-01-28 07:27:46 +00:00
} ,
{
statusCode : http . StatusOK ,
2023-05-09 11:18:47 +00:00
event : createTestEvent ( "push" , "library/test" , schema1 . MediaTypeSignedManifest ) , //nolint:staticcheck // Ignore SA1019: "github.com/distribution/distribution/v3/manifest/schema1" is deprecated, as it's used for backward compatibility.
2018-03-14 00:08:11 +00:00
} ,
{
statusCode : http . StatusOK ,
event : createTestEvent ( "push" , "library/test" , layerMediaType ) ,
} ,
{
statusCode : http . StatusOK ,
event : createTestEvent ( "push" , "library/test" , layerMediaType ) ,
2015-01-28 07:27:46 +00:00
} ,
{
statusCode : http . StatusTemporaryRedirect ,
} ,
{
statusCode : http . StatusBadRequest ,
2018-03-14 00:08:11 +00:00
isFailure : true ,
2015-01-28 07:27:46 +00:00
} ,
{
Fix unit test
If running test behide a proxy, we may get the error code
403 Forbidden which will fail line 135 for the last testcase.
Detail:
```
metrics not as expected: notifications.EndpointMetrics{Pending:0,
Events:0, Successes:4, Failures:0, Errors:0,
Statuses:map[string]int{"307 Temporary Redirect":0, "400 Bad Request":0,
"403 Forbidden":0, "200 OK":4}} !=
notifications.EndpointMetrics{Pending:0, Events:0, Successes:4,
Failures:0, Errors:0, Statuses:map[string]int{"400 Bad Request":0, "200
OK":4, "307 Temporary Redirect":0}}
```
Immediate close will fix that
Signed-off-by: Hu Keping <hukeping@huawei.com>
Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2017-01-10 01:10:49 +00:00
// Case where connection is immediately closed
2018-03-14 00:08:11 +00:00
url : "http://" + closeL . Addr ( ) . String ( ) ,
isError : true ,
2015-01-28 07:27:46 +00:00
} ,
} {
2018-03-14 00:08:11 +00:00
if tc . isFailure {
expectedMetrics . Failures ++
} else if tc . isError {
expectedMetrics . Errors ++
2015-01-28 07:27:46 +00:00
} else {
2018-03-14 00:08:11 +00:00
expectedMetrics . Successes ++
2015-01-28 07:27:46 +00:00
}
if tc . statusCode > 0 {
2018-03-14 00:08:11 +00:00
expectedMetrics . Statuses [ fmt . Sprintf ( "%d %s" , tc . statusCode , http . StatusText ( tc . statusCode ) ) ] ++
2015-01-28 07:27:46 +00:00
}
url := tc . url
if url == "" {
url = server . URL + "/"
}
// setup endpoint to respond with expected status code.
url += fmt . Sprintf ( "?status=%v" , tc . statusCode )
sink . url = url
2018-03-14 00:08:11 +00:00
t . Logf ( "testcase: %v, fail=%v, error=%v" , url , tc . isFailure , tc . isError )
2015-01-28 07:27:46 +00:00
// Try a simple event emission.
2018-03-14 00:08:11 +00:00
err := sink . Write ( tc . event )
2015-01-28 07:27:46 +00:00
2018-03-14 00:08:11 +00:00
if ! tc . isFailure && ! tc . isError {
2015-01-28 07:27:46 +00:00
if err != nil {
t . Fatalf ( "unexpected error send event: %v" , err )
}
} else {
if err == nil {
t . Fatalf ( "the endpoint should have rejected the request" )
}
2018-03-14 00:08:11 +00:00
t . Logf ( "write error: %v" , err )
2015-01-28 07:27:46 +00:00
}
if ! reflect . DeepEqual ( metrics . EndpointMetrics , expectedMetrics ) {
t . Fatalf ( "metrics not as expected: %#v != %#v" , metrics . EndpointMetrics , expectedMetrics )
}
}
if err := sink . Close ( ) ; err != nil {
t . Fatalf ( "unexpected error closing http sink: %v" , err )
}
// double close returns error
if err := sink . Close ( ) ; err == nil {
t . Fatalf ( "second close should have returned error: %v" , err )
}
}
func createTestEvent ( action , repo , typ string ) Event {
event := createEvent ( action )
2015-03-05 04:57:14 +00:00
event . Target . MediaType = typ
event . Target . Repository = repo
2015-01-28 07:27:46 +00:00
return * event
}