Skip to content

Commit

Permalink
working client instantiation.
Browse files Browse the repository at this point in the history
update SourceCredential interaface with additional GetEndpoint/Brand/Portal methods.
  • Loading branch information
AnalogJ committed Jan 13, 2024
1 parent dc575b5 commit 3c613ec
Show file tree
Hide file tree
Showing 45 changed files with 246 additions and 1,035 deletions.
47 changes: 40 additions & 7 deletions catalog/catalog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,31 +78,64 @@ func TestCatalog_GetEndpoints_WithSandboxMode(t *testing.T) {
require.Len(t, endpoints, 20)
}

func TestCatalog_GetEndpoints_HaveKnownPlatformType(t *testing.T) {
func TestCatalog_GetEndpoints_HaveKnownPlatformType_Production(t *testing.T) {
//setup
opts := modelsCatalog.CatalogQueryOptions{}
opts := modelsCatalog.CatalogQueryOptions{
LighthouseEnvType: pkg.FastenLighthouseEnvProduction,
}
endpoints, err := catalog.GetEndpoints(&opts)
require.NoError(t, err)

endpointPlatformTypes := map[pkg.PlatformType]bool{}
endpointPlatformTypes := map[pkg.PlatformType]string{}
knownPlatformTypes := pkg.GetPlatformTypes()

//test
for _, endpoint := range endpoints {
endpointPlatformTypes[endpoint.GetPlatformType()] = true
if _, exists := endpointPlatformTypes[endpoint.GetPlatformType()]; !exists {
endpointPlatformTypes[endpoint.GetPlatformType()] = endpoint.Id
}
}
foundAllEndpointPlatfromTypes := lo.EveryBy(lo.Keys(endpointPlatformTypes), func(platformType pkg.PlatformType) bool {
return lo.Contains(knownPlatformTypes, platformType)
})

for _, endpointPlatformType := range lo.Keys(endpointPlatformTypes) {
_, err := definitions.GetPlatformDefinition(endpointPlatformType, pkg.FastenLighthouseEnvProduction, map[pkg.PlatformType]string{})
for _, endpointId := range endpointPlatformTypes {
_, err := definitions.GetSourceDefinition(pkg.FastenLighthouseEnvProduction, map[pkg.PlatformType]string{}, definitions.GetSourceConfigOptions{EndpointId: endpointId})
require.NoError(t, err)
}

//assert

require.True(t, len(endpointPlatformTypes) >= 1)
require.True(t, foundAllEndpointPlatfromTypes)
}

func TestCatalog_GetEndpoints_HaveKnownPlatformType_Sandbox(t *testing.T) {
//setup
opts := modelsCatalog.CatalogQueryOptions{
LighthouseEnvType: pkg.FastenLighthouseEnvSandbox,
}
endpoints, err := catalog.GetEndpoints(&opts)
require.NoError(t, err)

endpointPlatformTypes := map[pkg.PlatformType]string{}
knownPlatformTypes := pkg.GetPlatformTypes()

//test
for _, endpoint := range endpoints {
if _, exists := endpointPlatformTypes[endpoint.GetPlatformType()]; !exists {
endpointPlatformTypes[endpoint.GetPlatformType()] = endpoint.Id
}
}
foundAllEndpointPlatfromTypes := lo.EveryBy(lo.Keys(endpointPlatformTypes), func(platformType pkg.PlatformType) bool {
return lo.Contains(knownPlatformTypes, platformType)
})

for _, endpointId := range endpointPlatformTypes {
_, err := definitions.GetSourceDefinition(pkg.FastenLighthouseEnvSandbox, map[pkg.PlatformType]string{}, definitions.GetSourceConfigOptions{EndpointId: endpointId})
require.NoError(t, err)
}

//assert
require.True(t, len(endpointPlatformTypes) >= 1)
require.True(t, foundAllEndpointPlatfromTypes)
}
89 changes: 13 additions & 76 deletions clients/factory/factory.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package platform
package internal

//
//func TestGetSourceClientAllscripts_SyncAll(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package platform
package internal

import (
"context"
Expand All @@ -21,14 +21,15 @@ func TestGetSourceClientAthena_SyncAll(t *testing.T) {
defer mockCtrl.Finish()
fakeDatabase := mock_models.NewMockDatabaseRepository(mockCtrl)
fakeDatabase.EXPECT().UpsertRawResource(gomock.Any(), gomock.Any(), gomock.Any()).Times(180).Return(true, nil)
fakeDatabase.EXPECT().BackgroundJobCheckpoint(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return()

fakeSourceCredential := mock_models.NewMockSourceCredential(mockCtrl)
fakeSourceCredential.EXPECT().GetPatientId().AnyTimes().Return("a-80000.E-14545")
fakeSourceCredential.EXPECT().GetSourceType().AnyTimes().Return(pkg.SourceTypeAthena)
fakeSourceCredential.EXPECT().GetApiEndpointBaseUrl().AnyTimes().Return("https://api.preview.platform.athenahealth.com/fhir/r4")
fakeSourceCredential.EXPECT().GetPlatformType().AnyTimes().Return(pkg.PlatformTypeAthena)
fakeSourceCredential.EXPECT().GetEndpointId().AnyTimes().Return("950e9092-8ce7-4926-ad87-64616f00cb4c")

httpClient := base.OAuthVcrSetup(t, false)
client, err := GetSourceClientAthena(pkg.FastenLighthouseEnvSandbox, context.Background(), testLogger, fakeSourceCredential, httpClient)
client, err := GetDynamicSourceClient(pkg.FastenLighthouseEnvSandbox, context.Background(), testLogger, fakeSourceCredential, httpClient)

//test
resp, err := client.SyncAll(fakeDatabase)
Expand Down
27 changes: 15 additions & 12 deletions clients/internal/base/base_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"github.com/fastenhealth/fasten-sources/clients/models"
definitionsModels "github.com/fastenhealth/fasten-sources/definitions/models"
"github.com/fastenhealth/fasten-sources/pkg"
"github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
Expand All @@ -28,9 +29,10 @@ type SourceClientBase struct {
Context context.Context
Logger logrus.FieldLogger

OauthClient *http.Client
SourceCredential models.SourceCredential
Headers map[string]string
OauthClient *http.Client
SourceCredential models.SourceCredential
EndpointDefinition *definitionsModels.LighthouseSourceDefinition
Headers map[string]string

UsCoreResources []string
FhirVersion string
Expand All @@ -49,14 +51,15 @@ func (c *SourceClientBase) ExtractPatientId(bundleFile *os.File) (string, pkg.Fh
panic("SyncAllBundle functionality is not available on this client")
}

func NewBaseClient(env pkg.FastenLighthouseEnvType, ctx context.Context, globalLogger logrus.FieldLogger, sourceCreds models.SourceCredential, testHttpClient ...*http.Client) (*SourceClientBase, error) {
func NewBaseClient(env pkg.FastenLighthouseEnvType, ctx context.Context, globalLogger logrus.FieldLogger, sourceCreds models.SourceCredential, endpointDefinition *definitionsModels.LighthouseSourceDefinition, testHttpClient ...*http.Client) (*SourceClientBase, error) {

client := &SourceClientBase{
FastenEnv: env,
Context: ctx,
Logger: globalLogger,
SourceCredential: sourceCreds,
Headers: map[string]string{},
FastenEnv: env,
Context: ctx,
Logger: globalLogger,
SourceCredential: sourceCreds,
EndpointDefinition: endpointDefinition,
Headers: map[string]string{},

// https://build.fhir.org/ig/HL7/US-Core/
UsCoreResources: []string{
Expand Down Expand Up @@ -127,8 +130,8 @@ func (c *SourceClientBase) RefreshAccessToken() error {
ClientID: c.SourceCredential.GetClientId(),
ClientSecret: "",
Endpoint: oauth2.Endpoint{
AuthURL: c.SourceCredential.GetOauthAuthorizationEndpoint(),
TokenURL: c.SourceCredential.GetOauthTokenEndpoint(),
AuthURL: c.EndpointDefinition.AuthorizationEndpoint,
TokenURL: c.EndpointDefinition.TokenEndpoint,
},
//RedirectURL: "",
//Scopes: nil,
Expand Down Expand Up @@ -214,7 +217,7 @@ func (c *SourceClientBase) GetRequest(resourceSubpathOrNext string, decodeModelP
return "", err
}
if !resourceUrl.IsAbs() {
resourceUrl, err = url.Parse(fmt.Sprintf("%s/%s", strings.TrimRight(c.SourceCredential.GetApiEndpointBaseUrl(), "/"), strings.TrimLeft(resourceSubpathOrNext, "/")))
resourceUrl, err = url.Parse(fmt.Sprintf("%s/%s", strings.TrimRight(c.EndpointDefinition.Url, "/"), strings.TrimLeft(resourceSubpathOrNext, "/")))
}
if err != nil {
return "", err
Expand Down
9 changes: 5 additions & 4 deletions clients/internal/base/fhir401_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"github.com/fastenhealth/fasten-sources/clients/models"
definitionsModels "github.com/fastenhealth/fasten-sources/definitions/models"
"github.com/fastenhealth/fasten-sources/pkg"
"github.com/fastenhealth/gofhir-models/fhir401"
fhirutils "github.com/fastenhealth/gofhir-models/fhir401/utils"
Expand All @@ -20,8 +21,8 @@ type SourceClientFHIR401 struct {
*SourceClientBase
}

func GetSourceClientFHIR401(env pkg.FastenLighthouseEnvType, ctx context.Context, globalLogger logrus.FieldLogger, sourceCreds models.SourceCredential, testHttpClient ...*http.Client) (*SourceClientFHIR401, error) {
baseClient, err := NewBaseClient(env, ctx, globalLogger, sourceCreds, testHttpClient...)
func GetSourceClientFHIR401(env pkg.FastenLighthouseEnvType, ctx context.Context, globalLogger logrus.FieldLogger, sourceCreds models.SourceCredential, endpointDefinition *definitionsModels.LighthouseSourceDefinition, testHttpClient ...*http.Client) (*SourceClientFHIR401, error) {
baseClient, err := NewBaseClient(env, ctx, globalLogger, sourceCreds, endpointDefinition, testHttpClient...)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -230,8 +231,8 @@ func (c *SourceClientFHIR401) ProcessPendingResources(db models.DatabaseReposito
for i, _ := range pendingResourceReferences {
pendingResourceId := pendingResourceReferences[i]
//convert absolute urls to relative url if possible
if strings.HasPrefix(pendingResourceId, c.SourceCredential.GetApiEndpointBaseUrl()) {
pendingResourceReferences[i] = strings.TrimPrefix(strings.TrimPrefix(pendingResourceId, c.SourceCredential.GetApiEndpointBaseUrl()), "/")
if strings.HasPrefix(pendingResourceId, c.EndpointDefinition.Url) {
pendingResourceReferences[i] = strings.TrimPrefix(strings.TrimPrefix(pendingResourceId, c.EndpointDefinition.Url), "/")
}
}

Expand Down
13 changes: 7 additions & 6 deletions clients/internal/base/fhir430_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"github.com/fastenhealth/fasten-sources/clients/models"
definitionsModels "github.com/fastenhealth/fasten-sources/definitions/models"
"github.com/fastenhealth/fasten-sources/pkg"
"github.com/fastenhealth/gofhir-models/fhir430"
fhirutils "github.com/fastenhealth/gofhir-models/fhir430/utils"
Expand All @@ -16,8 +17,8 @@ type SourceClientFHIR430 struct {
*SourceClientBase
}

func GetSourceClientFHIR430(env pkg.FastenLighthouseEnvType, ctx context.Context, globalLogger logrus.FieldLogger, sourceCreds models.SourceCredential, testHttpClient ...*http.Client) (*SourceClientFHIR430, error) {
baseClient, err := NewBaseClient(env, ctx, globalLogger, sourceCreds, testHttpClient...)
func GetSourceClientFHIR430(env pkg.FastenLighthouseEnvType, ctx context.Context, globalLogger logrus.FieldLogger, sourceCreds models.SourceCredential, endpointDefinition *definitionsModels.LighthouseSourceDefinition, testHttpClient ...*http.Client) (*SourceClientFHIR430, error) {
baseClient, err := NewBaseClient(env, ctx, globalLogger, sourceCreds, endpointDefinition, testHttpClient...)
if err != nil {
return nil, err
}
Expand All @@ -27,9 +28,9 @@ func GetSourceClientFHIR430(env pkg.FastenLighthouseEnvType, ctx context.Context
}, err
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FHIR
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func (c *SourceClientFHIR430) GetPatientEverything(patientId string) (*fhir430.Bundle, error) {

// https://www.hl7.org/fhir/patient-operation-everything.html
Expand All @@ -45,9 +46,9 @@ func (c *SourceClientFHIR430) GetPatient(patientId string) (*fhir430.Patient, er
return &patient, err
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Process Bundles
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func (c *SourceClientFHIR430) ProcessBundle(bundle fhir430.Bundle) ([]models.RawResourceFhir, error) {

//process each entry in bundle
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package platform
package internal

import (
"context"
Expand All @@ -20,22 +20,23 @@ func TestGetSourceClientCareevolution_SyncAll(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
fakeDatabase := mock_models.NewMockDatabaseRepository(mockCtrl)
fakeDatabase.EXPECT().UpsertRawResource(gomock.Any(), gomock.Any(), gomock.Any()).Times(158).Return(true, nil)
fakeDatabase.EXPECT().UpsertRawResource(gomock.Any(), gomock.Any(), gomock.Any()).Times(163).Return(true, nil)
fakeDatabase.EXPECT().BackgroundJobCheckpoint(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return()

fakeSourceCredential := mock_models.NewMockSourceCredential(mockCtrl)
fakeSourceCredential.EXPECT().GetPatientId().AnyTimes().Return("6709dc13-ca3e-4969-886a-fe0889eb8256")
fakeSourceCredential.EXPECT().GetSourceType().AnyTimes().Return(pkg.SourceTypeCareevolution)
fakeSourceCredential.EXPECT().GetApiEndpointBaseUrl().AnyTimes().Return("https://fhir.careevolution.com/Master.Adapter1.WebClient/api/fhir-r4")
fakeSourceCredential.EXPECT().GetPlatformType().AnyTimes().Return(pkg.PlatformTypeCareevolution)
fakeSourceCredential.EXPECT().GetEndpointId().AnyTimes().Return("8b47cf7b-330e-4ede-9967-4caa7be623aa")

httpClient := base.OAuthVcrSetup(t, false)
client, err := GetSourceClientCareevolution(pkg.FastenLighthouseEnvSandbox, context.Background(), testLogger, fakeSourceCredential, httpClient)
client, err := GetDynamicSourceClient(pkg.FastenLighthouseEnvSandbox, context.Background(), testLogger, fakeSourceCredential, httpClient)

//test
resp, err := client.SyncAll(fakeDatabase)
require.NoError(t, err)

//assert
require.NoError(t, err)
require.Equal(t, 164, resp.TotalResources)
require.Equal(t, 158, len(resp.UpdatedResources))
require.Equal(t, 163, resp.TotalResources)
require.Equal(t, 163, len(resp.UpdatedResources))
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package platform
package internal

import (
"context"
Expand All @@ -21,14 +21,15 @@ func TestGetSourceClientCerner_SyncAll(t *testing.T) {
defer mockCtrl.Finish()
fakeDatabase := mock_models.NewMockDatabaseRepository(mockCtrl)
fakeDatabase.EXPECT().UpsertRawResource(gomock.Any(), gomock.Any(), gomock.Any()).Times(853).Return(true, nil)
fakeDatabase.EXPECT().BackgroundJobCheckpoint(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return()

fakeSourceCredential := mock_models.NewMockSourceCredential(mockCtrl)
fakeSourceCredential.EXPECT().GetPatientId().AnyTimes().Return("12742397")
fakeSourceCredential.EXPECT().GetSourceType().AnyTimes().Return(pkg.SourceTypeCerner)
fakeSourceCredential.EXPECT().GetApiEndpointBaseUrl().AnyTimes().Return("https://fhir-myrecord.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d")
fakeSourceCredential.EXPECT().GetPlatformType().AnyTimes().Return(pkg.PlatformTypeCerner)
fakeSourceCredential.EXPECT().GetEndpointId().AnyTimes().Return("3290e5d7-978e-42ad-b661-1cf8a01a989c")

httpClient := base.OAuthVcrSetup(t, false)
client, err := GetSourceClientCerner(pkg.FastenLighthouseEnvSandbox, context.Background(), testLogger, fakeSourceCredential, httpClient)
client, err := GetDynamicSourceClient(pkg.FastenLighthouseEnvSandbox, context.Background(), testLogger, fakeSourceCredential, httpClient)

//test
resp, err := client.SyncAll(fakeDatabase)
Expand Down
73 changes: 73 additions & 0 deletions clients/internal/dynamic_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package internal

import (
"context"
"fmt"
base "github.com/fastenhealth/fasten-sources/clients/internal/base"
models "github.com/fastenhealth/fasten-sources/clients/models"
"github.com/fastenhealth/fasten-sources/definitions"
definitionsModels "github.com/fastenhealth/fasten-sources/definitions/models"
pkg "github.com/fastenhealth/fasten-sources/pkg"
logrus "github.com/sirupsen/logrus"
"net/http"
)

type dynamicSourceClient struct {
models.SourceClient
EndpointDefinition *definitionsModels.LighthouseSourceDefinition
}

func GetDynamicSourceClient(env pkg.FastenLighthouseEnvType, ctx context.Context, globalLogger logrus.FieldLogger, sourceCreds models.SourceCredential, testHttpClient ...*http.Client) (models.SourceClient, error) {

//get the endpoint definition
endpointDefinition, err := definitions.GetSourceDefinition(env, map[pkg.PlatformType]string{}, definitions.GetSourceConfigOptions{
EndpointId: sourceCreds.GetEndpointId(),
})
if err != nil {
return nil, err
}
if endpointDefinition == nil {
return nil, fmt.Errorf("error retrieving endpoint definition (%s)", sourceCreds.GetEndpointId())
}

baseClient, err := base.GetSourceClientFHIR401(env, ctx, globalLogger, sourceCreds, endpointDefinition, testHttpClient...)
if err != nil {
return nil, err
}

// API requires the following headers for every request
if len(endpointDefinition.ClientHeaders) > 0 {
for k, v := range endpointDefinition.ClientHeaders {
baseClient.Headers[k] = v
}
}

return dynamicSourceClient{SourceClient: baseClient, EndpointDefinition: endpointDefinition}, err
}

func (c dynamicSourceClient) SyncAll(db models.DatabaseRepository) (models.UpsertSummary, error) {

if c.EndpointDefinition.MissingOpPatientEverything {
//Operation-PatientEverything is not supported - https://build.fhir.org/operation-patient-everything.html
//Manually processing individual resources

supportedResources := c.GetUsCoreResources()
if c.EndpointDefinition.ClientSupportedResources != nil {
supportedResources = append(supportedResources, c.EndpointDefinition.ClientSupportedResources...)
}
return c.SyncAllByResourceName(db, supportedResources)
} else if len(c.EndpointDefinition.CustomOpPatientEverything) > 0 {
//Operation-PatientEverything uses non-standard endpoint - https://build.fhir.org/operation-patient-everything.html

bundle, err := c.GetResourceBundle(c.EndpointDefinition.CustomOpPatientEverything)
if err != nil {
return models.UpsertSummary{UpdatedResources: []string{}}, err
}
return c.SyncAllByPatientEverythingBundle(db, bundle)
} else {
//Standard Operation-PatientEverything

return c.SourceClient.SyncAll(db)
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package platform
package internal

import (
"context"
Expand All @@ -21,14 +21,15 @@ func TestGetSourceClientEpic_SyncAll(t *testing.T) {
defer mockCtrl.Finish()
fakeDatabase := mock_models.NewMockDatabaseRepository(mockCtrl)
fakeDatabase.EXPECT().UpsertRawResource(gomock.Any(), gomock.Any(), gomock.Any()).Times(13).Return(true, nil)
fakeDatabase.EXPECT().BackgroundJobCheckpoint(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return()

fakeSourceCredential := mock_models.NewMockSourceCredential(mockCtrl)
fakeSourceCredential.EXPECT().GetPatientId().AnyTimes().Return("erXuFYUfucBZaryVksYEcMg3")
fakeSourceCredential.EXPECT().GetSourceType().AnyTimes().Return(pkg.SourceTypeEpic)
fakeSourceCredential.EXPECT().GetApiEndpointBaseUrl().AnyTimes().Return("https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4")
fakeSourceCredential.EXPECT().GetPlatformType().AnyTimes().Return(pkg.PlatformTypeEpic)
fakeSourceCredential.EXPECT().GetEndpointId().AnyTimes().Return("8e2f5de7-46ac-4067-96ba-5e3f60ad52a4")

httpClient := base.OAuthVcrSetup(t, false)
client, err := GetSourceClientEpic(pkg.FastenLighthouseEnvSandbox, context.Background(), testLogger, fakeSourceCredential, httpClient)
client, err := GetDynamicSourceClient(pkg.FastenLighthouseEnvSandbox, context.Background(), testLogger, fakeSourceCredential, httpClient)

//test
resp, err := client.SyncAll(fakeDatabase)
Expand Down
Loading

0 comments on commit 3c613ec

Please sign in to comment.