diff --git a/bulkfhir/auth.go b/bulkfhir/auth.go index ddd9d20..980acf8 100644 --- a/bulkfhir/auth.go +++ b/bulkfhir/auth.go @@ -65,8 +65,8 @@ type Authenticator interface { AddAuthenticationToRequest(hc *http.Client, req *http.Request) error } -// bearerToken encapsulates a bearer token presented as an Authorization header. -type bearerToken struct { +// BearerToken encapsulates a bearer token presented as an Authorization header. +type BearerToken struct { token string expiry time.Time alwaysAuthenticateIfNoExpiry bool @@ -80,7 +80,7 @@ type bearerToken struct { // from a previous request, or a default expiry set when the authenticator // was created. // - No expiry time is available, and alwaysAuthenticateIfNoExpiry is true. -func (bt *bearerToken) shouldRenew() bool { +func (bt *BearerToken) shouldRenew() bool { if bt == nil || bt.token == "" { return true } @@ -94,32 +94,32 @@ func (bt *bearerToken) shouldRenew() bool { return false } -func (bt *bearerToken) addHeader(req *http.Request) { +func (bt *BearerToken) addHeader(req *http.Request) { req.Header.Set(authorizationHeader, fmt.Sprintf("Bearer %s", bt.token)) } -// credentialExchanger is used by bearerTokenAuthenticator to exchange +// CredentialExchanger is used by bearerTokenAuthenticator to exchange // long-lived credentials for a short lived bearer token. -type credentialExchanger interface { - authenticate(hc *http.Client) (*bearerToken, error) +type CredentialExchanger interface { + Authenticate(hc *http.Client) (*BearerToken, error) } -// bearerTokenAuthenticator is an implementation of Authenticator which uses a -// credentialExchanger to obtain a bearer token which is presented in an +// BearerTokenAuthenticator is an implementation of Authenticator which uses a +// CredentialExchanger to obtain a bearer token which is presented in an // Authorization header. // // Note: this implementation is not thread safe. -type bearerTokenAuthenticator struct { - exchanger credentialExchanger - token *bearerToken +type BearerTokenAuthenticator struct { + Exchanger CredentialExchanger + token *BearerToken } // Authenticate is Authenticator.Authenticate. // -// This Authenticator uses the credentialExchanger it contains to obtain a +// This Authenticator uses the CredentialExchanger it contains to obtain a // bearer token. -func (bta *bearerTokenAuthenticator) Authenticate(hc *http.Client) error { - token, err := bta.exchanger.authenticate(hc) +func (bta *BearerTokenAuthenticator) Authenticate(hc *http.Client) error { + token, err := bta.Exchanger.Authenticate(hc) if err != nil { return err } @@ -129,9 +129,9 @@ func (bta *bearerTokenAuthenticator) Authenticate(hc *http.Client) error { // AuthenticateIfNecessary is Authenticator.AuthenticateIfNecessary. // -// This Authenticator uses the credentialExchanger it contains to obtain a +// This Authenticator uses the CredentialExchanger it contains to obtain a // bearer token. -func (bta *bearerTokenAuthenticator) AuthenticateIfNecessary(hc *http.Client) error { +func (bta *BearerTokenAuthenticator) AuthenticateIfNecessary(hc *http.Client) error { if bta.token.shouldRenew() { return bta.Authenticate(hc) } @@ -142,7 +142,7 @@ func (bta *bearerTokenAuthenticator) AuthenticateIfNecessary(hc *http.Client) er // // This Authenticator adds an access token as an Authorization: Bearer {token} // header, automatically requesting/refreshing the token as necessary. -func (bta *bearerTokenAuthenticator) AddAuthenticationToRequest(hc *http.Client, req *http.Request) error { +func (bta *BearerTokenAuthenticator) AddAuthenticationToRequest(hc *http.Client, req *http.Request) error { if err := bta.AuthenticateIfNecessary(hc); err != nil { return err } @@ -201,8 +201,8 @@ func (tr *tokenResponse) UnmarshalJSON(data []byte) error { return nil } -func (tr *tokenResponse) toBearerToken(defaultExpiry time.Duration, alwaysAuthenticateIfNoExpiry bool) *bearerToken { - bt := &bearerToken{ +func (tr *tokenResponse) toBearerToken(defaultExpiry time.Duration, alwaysAuthenticateIfNoExpiry bool) *BearerToken { + bt := &BearerToken{ token: tr.Token, alwaysAuthenticateIfNoExpiry: alwaysAuthenticateIfNoExpiry, } @@ -214,9 +214,9 @@ func (tr *tokenResponse) toBearerToken(defaultExpiry time.Duration, alwaysAuthen return bt } -// doOAuthExchange sends a HTTP request which is expected to return a JSON -// response matching tokenResponse. -func doOAuthExchange(hc *http.Client, req *http.Request, defaultExpiry time.Duration, alwaysAuthenticateIfNoExpiresIn bool) (*bearerToken, error) { +// DoOAuthExchange sends a HTTP request which is expected to return a JSON +// response with "token" and "expires_in" fields. +func DoOAuthExchange(hc *http.Client, req *http.Request, defaultExpiry time.Duration, alwaysAuthenticateIfNoExpiresIn bool) (*BearerToken, error) { resp, err := hc.Do(req) if err != nil { return nil, err @@ -239,7 +239,7 @@ func doOAuthExchange(hc *http.Client, req *http.Request, defaultExpiry time.Dura return tr.toBearerToken(defaultExpiry, alwaysAuthenticateIfNoExpiresIn), nil } -// httpBasicOAuthExchanger is an implementation of credentialExchanger for use +// httpBasicOAuthExchanger is an implementation of CredentialExchanger for use // with bearerTokenAuthenticator which performs a 2-legged OAuth2 handshake // using HTTP Basic Authentication to obtain an access token, which is presented // as an "Authorization: Bearer {token}" header in all requests. @@ -267,11 +267,11 @@ func (hboe *httpBasicOAuthExchanger) buildBody() io.Reader { return bytes.NewBufferString(v.Encode()) } -// authenticate is credentialExchanger.authenticate. +// Authenticate is CredentialExchanger.Authenticate. // -// This credentialExchanger performs 2-legged OAuth using HTTP Basic +// This CredentialExchanger performs 2-legged OAuth using HTTP Basic // Authentication to obtain an expiry token. -func (hboe *httpBasicOAuthExchanger) authenticate(hc *http.Client) (*bearerToken, error) { +func (hboe *httpBasicOAuthExchanger) Authenticate(hc *http.Client) (*BearerToken, error) { req, err := http.NewRequest(http.MethodPost, hboe.tokenURL, hboe.buildBody()) if err != nil { return nil, err @@ -281,7 +281,7 @@ func (hboe *httpBasicOAuthExchanger) authenticate(hc *http.Client) (*bearerToken req.Header.Add(acceptHeader, acceptHeaderJSON) req.Header.Add(contentTypeHeader, contentTypeFormURLEncoded) - return doOAuthExchange(hc, req, hboe.defaultExpiry, hboe.alwaysAuthenticateIfNoExpiresIn) + return DoOAuthExchange(hc, req, hboe.defaultExpiry, hboe.alwaysAuthenticateIfNoExpiresIn) } // HTTPBasicOAuthOptions contains optional parameters used by @@ -332,7 +332,7 @@ func NewHTTPBasicOAuthAuthenticator(username, password, tokenURL string, opts *H e.defaultExpiry = opts.DefaultExpiry } - return &bearerTokenAuthenticator{exchanger: e}, nil + return &BearerTokenAuthenticator{Exchanger: e}, nil } // A JWTKeyProvider provides the RSA private key used for signing JSON Web Tokens. @@ -420,11 +420,11 @@ func (joe *jwtOAuthExchanger) buildBody() (io.Reader, error) { return bytes.NewBufferString(v.Encode()), nil } -// authenticate is credentialExchanger.authenticate. +// Authenticate is CredentialExchanger.Authenticate. // -// This credentialExchanger performs 2-legged OAuth using HTTP Basic +// This CredentialExchanger performs 2-legged OAuth using HTTP Basic // Authentication to obtain an expiry token. -func (joe *jwtOAuthExchanger) authenticate(hc *http.Client) (*bearerToken, error) { +func (joe *jwtOAuthExchanger) Authenticate(hc *http.Client) (*BearerToken, error) { body, err := joe.buildBody() if err != nil { return nil, err @@ -437,7 +437,7 @@ func (joe *jwtOAuthExchanger) authenticate(hc *http.Client) (*bearerToken, error req.Header.Add(acceptHeader, acceptHeaderJSON) req.Header.Add(contentTypeHeader, contentTypeFormURLEncoded) - return doOAuthExchange(hc, req, joe.defaultExpiry, joe.alwaysAuthenticateIfNoExpiresIn) + return DoOAuthExchange(hc, req, joe.defaultExpiry, joe.alwaysAuthenticateIfNoExpiresIn) } // JWTOAuthOptions contains optional parameters used by NewJWTOAuthAuthenticator. @@ -494,5 +494,5 @@ func NewJWTOAuthAuthenticator(issuer, subject, tokenURL string, keyProvider JWTK } } - return &bearerTokenAuthenticator{exchanger: e}, nil + return &BearerTokenAuthenticator{Exchanger: e}, nil } diff --git a/bulkfhir/client_test.go b/bulkfhir/client_test.go index 85b9899..c951e53 100644 --- a/bulkfhir/client_test.go +++ b/bulkfhir/client_test.go @@ -611,7 +611,7 @@ func TestClient_MonitorJobStatus(t *testing.T) { if err != nil { t.Fatal(err) } - auth.(*bearerTokenAuthenticator).token = &bearerToken{ + auth.(*BearerTokenAuthenticator).token = &BearerToken{ token: "123", expiry: time.Now().Add(5 * time.Minute), } diff --git a/fhir/processing/bcdarectify_test.go b/fhir/processing/bcdarectify_test.go index 2c5267b..6bb6262 100644 --- a/fhir/processing/bcdarectify_test.go +++ b/fhir/processing/bcdarectify_test.go @@ -102,7 +102,7 @@ func TestBcdaRectifyProcessor(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - ts := &testSink{} + ts := &processing.TestSink{} p, err := processing.NewPipeline([]processing.Processor{processing.NewBCDARectifyProcessor()}, []processing.Sink{ts}) if err != nil { t.Fatalf("NewPipeline() returned unexpected error: %v", err) @@ -110,7 +110,7 @@ func TestBcdaRectifyProcessor(t *testing.T) { if err := p.Process(context.Background(), tc.resourceType, "", tc.jsonIn); err != nil { t.Fatalf("pipeline.Process(..., %s) returned unexpected error: %v", tc.jsonIn, err) } - gotJSON, err := ts.writtenResources[0].JSON() + gotJSON, err := ts.WrittenResources[0].JSON() if err != nil { t.Fatalf("writtenResource.JSON() returned unexpected error: %v", err) } diff --git a/fhir/processing/documents_test.go b/fhir/processing/documents_test.go index c5754a6..594912c 100644 --- a/fhir/processing/documents_test.go +++ b/fhir/processing/documents_test.go @@ -91,7 +91,7 @@ func TestDocumentsProcessor(t *testing.T) { t.Fatal(err) } defer os.RemoveAll(tempdir) - ts := &testSink{} + ts := &processing.TestSink{} authenticator, err := bulkfhir.NewHTTPBasicOAuthAuthenticator("username", "password", server.URL+"/auth", nil) if err != nil { t.Fatal(err) @@ -121,7 +121,7 @@ func TestDocumentsProcessor(t *testing.T) { // that the filename in the output resource exists, and then populate the // wanted resource with the filename that was written. - gotResource, err := ts.writtenResources[0].Proto() + gotResource, err := ts.WrittenResources[0].Proto() if err != nil { t.Fatalf("writtenResource.Proto() returned unexpected error: %v", err) } @@ -139,7 +139,7 @@ func TestDocumentsProcessor(t *testing.T) { tc.wantJSON = strings.Replace(tc.wantJSON, fmt.Sprintf("FILEPATH%d", i), strings.ReplaceAll(url, `\`, `\\`), 1) } - gotJSON, err := ts.writtenResources[0].JSON() + gotJSON, err := ts.WrittenResources[0].JSON() if err != nil { t.Fatalf("writtenResource.JSON() returned unexpected error: %v", err) } diff --git a/fhir/processing/processing_test.go b/fhir/processing/processing_test.go index e31d273..ba11efa 100644 --- a/fhir/processing/processing_test.go +++ b/fhir/processing/processing_test.go @@ -34,8 +34,8 @@ func (tp *testProcessor) Process(ctx context.Context, resource processing.Resour } func TestTeeFHIRSink(t *testing.T) { - ts1 := &testSink{} - ts2 := &testSink{} + ts1 := &processing.TestSink{} + ts2 := &processing.TestSink{} ctx := context.Background() p, err := processing.NewPipeline([]processing.Processor{&testProcessor{}}, []processing.Sink{ts1, ts2}) if err != nil { @@ -50,24 +50,24 @@ func TestTeeFHIRSink(t *testing.T) { if err := p.Finalize(ctx); err != nil { t.Fatalf("p.Finalize() returned unexpected error: %v", err) } - for i, ts := range []*testSink{ts1, ts2} { - if len(ts.writtenResources) != 1 { - t.Fatalf("testSink %d captured %d resources, want 1", i, len(ts.writtenResources)) + for i, ts := range []*processing.TestSink{ts1, ts2} { + if len(ts.WrittenResources) != 1 { + t.Fatalf("TestSink %d captured %d resources, want 1", i, len(ts.WrittenResources)) } - if ts.writtenResources[0].Type() != resourceType { - t.Errorf("testSink %d captured unexpected resource type: got %s, want %s", i, ts.writtenResources[0].Type(), resourceType) + if ts.WrittenResources[0].Type() != resourceType { + t.Errorf("TestSink %d captured unexpected resource type: got %s, want %s", i, ts.WrittenResources[0].Type(), resourceType) } - if ts.writtenResources[0].SourceURL() != sourceURL { - t.Errorf("testSink %d captured unexpected resource type: got %q, want %q", i, ts.writtenResources[0].SourceURL(), sourceURL) + if ts.WrittenResources[0].SourceURL() != sourceURL { + t.Errorf("TestSink %d captured unexpected resource type: got %q, want %q", i, ts.WrittenResources[0].SourceURL(), sourceURL) } - json, err := ts.writtenResources[0].JSON() + json, err := ts.WrittenResources[0].JSON() if err != nil { - t.Errorf("testSink %d JSON() returned unexpected error: %v", i, err) + t.Errorf("TestSink %d JSON() returned unexpected error: %v", i, err) } else if !cmp.Equal(json, data) { - t.Errorf("testSink %d captured unexpected data: got %s, want %s", i, json, data) + t.Errorf("TestSink %d captured unexpected data: got %s, want %s", i, json, data) } - if !ts.finalizeCalled { - t.Errorf("Finalize not called on testSink %d", i) + if !ts.FinalizeCalled { + t.Errorf("Finalize not called on TestSink %d", i) } } } diff --git a/fhir/processing/testsink_test.go b/fhir/processing/testsink.go similarity index 53% rename from fhir/processing/testsink_test.go rename to fhir/processing/testsink.go index 7fab047..f1faa43 100644 --- a/fhir/processing/testsink_test.go +++ b/fhir/processing/testsink.go @@ -12,29 +12,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -package processing_test +package processing import ( "context" - - "github.com/google/medical_claims_tools/fhir/processing" ) -// testSink can be used for testing processors by capturing processed resources. -type testSink struct { - writtenResources []processing.ResourceWrapper - finalizeCalled bool +// TestSink can be used for testing processors by capturing processed resources. +type TestSink struct { + WrittenResources []ResourceWrapper + FinalizeCalled bool } -func (ts *testSink) Write(ctx context.Context, resource processing.ResourceWrapper) error { - ts.writtenResources = append(ts.writtenResources, resource) +// Write is Sink.Write +func (ts *TestSink) Write(ctx context.Context, resource ResourceWrapper) error { + ts.WrittenResources = append(ts.WrittenResources, resource) return nil } -func (ts *testSink) Finalize(ctx context.Context) error { - ts.finalizeCalled = true +// Finalize is Sink.Finalize +func (ts *TestSink) Finalize(ctx context.Context) error { + ts.FinalizeCalled = true return nil } -// Assert that testSink satisfies the Sink interface. -var _ processing.Sink = &testSink{} +// Assert that TestSink satisfies the Sink interface. +var _ Sink = &TestSink{}