fasten-onprem/backend/pkg/database/sqlite_repository_test.go

1383 lines
56 KiB
Go

package database
import (
"encoding/json"
"fmt"
"github.com/fastenhealth/fasten-onprem/backend/pkg"
mock_config "github.com/fastenhealth/fasten-onprem/backend/pkg/config/mock"
"github.com/fastenhealth/fasten-onprem/backend/pkg/event_bus"
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
sourceModels "github.com/fastenhealth/fasten-sources/clients/models"
sourcePkg "github.com/fastenhealth/fasten-sources/pkg"
"github.com/fastenhealth/gofhir-models/fhir401"
fhirutils "github.com/fastenhealth/gofhir-models/fhir401/utils"
"github.com/gin-gonic/gin"
"github.com/golang/mock/gomock"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"golang.org/x/net/context"
"io/ioutil"
"log"
"net/http/httptest"
"os"
"testing"
"time"
)
func TestSourceCredentialInterface(t *testing.T) {
t.Parallel()
repo := new(SqliteRepository)
//assert
require.Implements(t, (*sourceModels.DatabaseRepository)(nil), repo, "should implement the DatabaseRepository interface from fasten-sources")
require.Implements(t, (*DatabaseRepository)(nil), repo, "should implement the DatabaseRepository interface")
}
// Define the suite, and absorb the built-in basic suite
// functionality from testify - including a T() method which
// returns the current testing context
type RepositoryTestSuite struct {
suite.Suite
MockCtrl *gomock.Controller
TestDatabase *os.File
}
// BeforeTest has a function to be executed right before the test starts and receives the suite and test names as input
func (suite *RepositoryTestSuite) BeforeTest(suiteName, testName string) {
suite.MockCtrl = gomock.NewController(suite.T())
dbFile, err := ioutil.TempFile("", fmt.Sprintf("%s.*.db", testName))
if err != nil {
log.Fatal(err)
}
suite.TestDatabase = dbFile
}
// AfterTest has a function to be executed right after the test finishes and receives the suite and test names as input
func (suite *RepositoryTestSuite) AfterTest(suiteName, testName string) {
suite.MockCtrl.Finish()
os.Remove(suite.TestDatabase.Name())
}
// In order for 'go test' to run this suite, we need to create
// a normal test function and pass our suite to suite.Run
func TestRepositoryTestSuite(t *testing.T) {
suite.Run(t, new(RepositoryTestSuite))
}
func (suite *RepositoryTestSuite) TestNewRepository() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
//test
_, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
//assert
require.NoError(suite.T(), err)
}
func (suite *RepositoryTestSuite) TestCreateUser() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
//test
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
dbRepo.CreateUser(context.Background(), userModel)
//assert
require.NotEmpty(suite.T(), userModel.ID)
}
func (suite *RepositoryTestSuite) TestCreateUser_WithExitingUser_ShouldFail() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
//test
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
userModel2 := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel2)
//assert
require.Error(suite.T(), err)
}
// TODO: ensure user's cannot specify the ID when creating a user.
func (suite *RepositoryTestSuite) TestCreateUser_WithUserProvidedId_ShouldBeReplaced() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
//test
userProvidedId := uuid.New()
userModel := &models.User{
ModelBase: models.ModelBase{
ID: userProvidedId,
},
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
dbRepo.CreateUser(context.Background(), userModel)
//assert
require.NotEmpty(suite.T(), userModel.ID)
require.NotEqual(suite.T(), userProvidedId.String(), userModel.ID.String())
}
func (suite *RepositoryTestSuite) TestGetUserByUsername() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
//test
userModelResult, err := dbRepo.GetUserByUsername(context.Background(), "test_username")
//assert
require.NoError(suite.T(), err)
require.Equal(suite.T(), userModel.ID, userModelResult.ID)
}
func (suite *RepositoryTestSuite) TestGetUserByUsername_WithInvalidUsername() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
//test
_, err = dbRepo.GetUserByUsername(context.Background(), "userdoesntexist")
//assert
require.Error(suite.T(), err)
}
func (suite *RepositoryTestSuite) TestGetCurrentUser_WithContextBackgroundAuthUser() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
//test
userModelResult, err := dbRepo.GetCurrentUser(context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username"))
//assert
require.NoError(suite.T(), err)
require.NotNil(suite.T(), userModelResult)
require.Equal(suite.T(), userModelResult.Username, "test_username")
}
func (suite *RepositoryTestSuite) TestGetCurrentUser_WithGinContextBackgroundAuthUser() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
//test
//ginContext := gin.Context{}
w := httptest.NewRecorder()
ginContext, _ := gin.CreateTestContext(w)
ginContext.Set(pkg.ContextKeyTypeAuthUsername, "test_username")
userModelResult, err := dbRepo.GetCurrentUser(ginContext)
//assert
require.NoError(suite.T(), err)
require.NotNil(suite.T(), userModelResult)
require.Equal(suite.T(), userModelResult.Username, "test_username")
}
func (suite *RepositoryTestSuite) TestGetCurrentUser_WithContextBackgroundAuthUserAndNoUserExists_ShouldThrowError() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
//test
userModelResult, err := dbRepo.GetCurrentUser(context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username"))
//assert
require.Error(suite.T(), err)
require.Nil(suite.T(), userModelResult)
}
func (suite *RepositoryTestSuite) TestCreateGlossaryEntry() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
//test
glossaryEntry := &models.Glossary{
Code: "49727002",
CodeSystem: "2.16.840.1.113883.6.96",
Publisher: "U.S. National Library of Medicine",
Title: "Cough",
Url: "https://medlineplus.gov/cough.html?utm_source=mplusconnect&utm_medium=service",
Description: `<p>Coughing is a reflex that keeps your throat and airways clear. Although it can be annoying, coughing helps your body heal or protect itself. Coughs can be either acute or chronic. Acute coughs begin suddenly and usually last no more than 2 to 3 weeks. Acute coughs are the kind you most often get with a <a href="https://medlineplus.gov/commoncold.html?utm_source=mplusconnect">cold</a>, <a href="https://medlineplus.gov/flu.html?utm_source=mplusconnect">flu</a>, or <a href="https://medlineplus.gov/acutebronchitis.html?utm_source=mplusconnect">acute bronchitis</a>. Chronic coughs last longer than 2 to 3 weeks. Causes of chronic cough include:</p><ul>
<li><a href="https://medlineplus.gov/chronicbronchitis.html?utm_source=mplusconnect">Chronic bronchitis</a></li>
<li><a href="https://medlineplus.gov/asthma.html?utm_source=mplusconnect">Asthma</a></li>
<li><a href="https://medlineplus.gov/allergy.html?utm_source=mplusconnect">Allergies</a></li>
<li><a href="https://medlineplus.gov/copd.html?utm_source=mplusconnect">COPD</a> (chronic obstructive pulmonary disease)</li>
<li><a href="https://medlineplus.gov/gerd.html?utm_source=mplusconnect">GERD</a> (gastroesophageal reflux disease) </li>
<li><a href="https://medlineplus.gov/smoking.html?utm_source=mplusconnect">Smoking</a></li>
<li><a href="https://medlineplus.gov/throatdisorders.html?utm_source=mplusconnect">Throat disorders</a>, such as <a href="https://medlineplus.gov/croup.html?utm_source=mplusconnect">croup</a> in young children</li>
<li>Some medicines </li>
</ul>
<p>Water can help ease your cough - whether you drink it or add it to the air with a steamy shower or vaporizer. If you have a cold or the flu, antihistamines may work better than non-prescription <a href="https://medlineplus.gov/coldandcoughmedicines.html?utm_source=mplusconnect">cough medicines</a>. Children under four should not have cough medicine. For children over four, use caution and read labels carefully.</p>`,
}
err = dbRepo.CreateGlossaryEntry(context.Background(), glossaryEntry)
//assert
require.NoError(suite.T(), err)
require.NotEmpty(suite.T(), glossaryEntry.ID)
}
func (suite *RepositoryTestSuite) TestUpsertRawResource() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
testPatientData, err := os.ReadFile("./testdata/Abraham100_Heller342_Patient.json")
require.NoError(suite.T(), err)
//test
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
wasCreated, err := dbRepo.UpsertRawResource(
authContext,
&testSourceCredential,
sourceModels.RawResourceFhir{
SourceResourceType: "Patient",
SourceResourceID: "b426b062-8273-4b93-a907-de3176c0567d",
ResourceRaw: testPatientData,
},
)
require.NoError(suite.T(), err)
foundPatientResource, err := dbRepo.GetResourceByResourceTypeAndId(authContext, "Patient", "b426b062-8273-4b93-a907-de3176c0567d")
//assert
require.NoError(suite.T(), err)
require.True(suite.T(), wasCreated)
require.NotNil(suite.T(), foundPatientResource)
require.Equal(suite.T(), foundPatientResource.SourceID, testSourceCredential.ID)
//ensure that the raw resource data is the same (we don't want to modify the data)
var expectedPationData map[string]interface{}
err = json.Unmarshal(testPatientData, &expectedPationData)
require.NoError(suite.T(), err)
var actualPatientData map[string]interface{}
err = json.Unmarshal(foundPatientResource.ResourceRaw, &actualPatientData)
require.Equal(suite.T(), expectedPationData, actualPatientData)
}
//TODO create UPSERT test, where the resource already exists and we need to update it
func (suite *RepositoryTestSuite) TestUpsertRawResource_WithRelatedResourceAndDuplicateReference() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
patientData, err := os.ReadFile("./testdata/Abraham100_Heller342_Patient.json")
require.NoError(suite.T(), err)
//test
wasCreated, err := dbRepo.UpsertRawResource(
context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username"),
&testSourceCredential,
sourceModels.RawResourceFhir{
SourceResourceType: "Patient",
SourceResourceID: "b426b062-8273-4b93-a907-de3176c0567d",
ResourceRaw: patientData,
ReferencedResources: []string{"Observation/1", "Observation/2", "Observation/3", "Observation/3"}, //duplicate resource reference should not cause an issue, it should be silently ignored
},
)
//assert
require.NoError(suite.T(), err)
require.True(suite.T(), wasCreated)
relatedResource, err := dbRepo.FindResourceAssociationsByTypeAndId(authContext, &testSourceCredential, "Patient", "b426b062-8273-4b93-a907-de3176c0567d")
require.NoError(suite.T(), err)
require.Equal(suite.T(), 3, len(relatedResource))
}
func (suite *RepositoryTestSuite) TestListResources() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
otherUserModel := &models.User{
Username: "test_other_username",
Password: "testpassword",
Email: "testother@test.com",
}
err = dbRepo.CreateUser(context.Background(), otherUserModel)
require.NoError(suite.T(), err)
testSource1Credential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
testSource2Credential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
patientDataAbraham100, err := os.ReadFile("./testdata/Abraham100_Heller342_Patient.json")
require.NoError(suite.T(), err)
testResource1Created, err := dbRepo.UpsertRawResource(
context.WithValue(authContext, pkg.ContextKeyTypeAuthUsername, "test_username"),
&testSource1Credential,
sourceModels.RawResourceFhir{
SourceResourceType: "Patient",
SourceResourceID: "b426b062-8273-4b93-a907-de3176c0567d",
ResourceRaw: patientDataAbraham100,
ReferencedResources: []string{"Observation/1", "Observation/2", "Observation/3", "Observation/3"}, //duplicate resource reference should not cause an issue, it should be silently ignored
},
)
require.NoError(suite.T(), err)
require.True(suite.T(), testResource1Created)
patientDataLillia547, err := os.ReadFile("./testdata/Lillia547_Schneider99_Patient.json")
require.NoError(suite.T(), err)
testResource2Created, err := dbRepo.UpsertRawResource(
context.WithValue(authContext, pkg.ContextKeyTypeAuthUsername, "test_username"),
&testSource2Credential,
sourceModels.RawResourceFhir{
SourceResourceType: "Patient",
SourceResourceID: "d3fbfb3a-7b8d-45c0-13b4-9666e4d36a3e",
ResourceRaw: patientDataLillia547,
ReferencedResources: []string{"Observation/10", "Observation/20", "Observation/30"},
},
)
require.NoError(suite.T(), err)
require.True(suite.T(), testResource2Created)
//test
foundPatientResources, err := dbRepo.ListResources(authContext, models.ListResourceQueryOptions{
SourceResourceType: "Patient",
})
require.NoError(suite.T(), err)
findAllResources, err := dbRepo.ListResources(authContext, models.ListResourceQueryOptions{})
require.NoError(suite.T(), err)
findSourceResources, err := dbRepo.ListResources(authContext, models.ListResourceQueryOptions{SourceID: testSource1Credential.ID.String()})
require.NoError(suite.T(), err)
//find specific resource
findSpecificResource, err := dbRepo.ListResources(authContext, models.ListResourceQueryOptions{SourceResourceID: "d3fbfb3a-7b8d-45c0-13b4-9666e4d36a3e", SourceResourceType: "Patient"})
require.NoError(suite.T(), err)
findInvalidResource, err := dbRepo.ListResources(authContext, models.ListResourceQueryOptions{SourceResourceID: "11111111-7b8d-45c0-13b4-9666e4d36a3e", SourceResourceType: "Patient"})
require.NoError(suite.T(), err)
findResourceWithOtherUserId, err := dbRepo.ListResources(context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_other_username"), models.ListResourceQueryOptions{SourceResourceID: "d3fbfb3a-7b8d-45c0-13b4-9666e4d36a3e", SourceResourceType: "Patient"})
require.NoError(suite.T(), err)
_, err = dbRepo.ListResources(context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "doesnt_exist"), models.ListResourceQueryOptions{SourceResourceID: "d3fbfb3a-7b8d-45c0-13b4-9666e4d36a3e", SourceResourceType: "Patient"})
require.Error(suite.T(), err)
//assert
require.Equal(suite.T(), len(foundPatientResources), 2)
require.Equal(suite.T(), len(findAllResources), 2)
require.Equal(suite.T(), len(findSourceResources), 1)
require.Equal(suite.T(), len(findSpecificResource), 1)
require.Equal(suite.T(), len(findInvalidResource), 0)
require.Equal(suite.T(), len(findResourceWithOtherUserId), 0)
}
func (suite *RepositoryTestSuite) TestGetResourceByResourceTypeAndId() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
testPatientData, err := os.ReadFile("./testdata/Abraham100_Heller342_Patient.json")
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
wasCreated, err := dbRepo.UpsertRawResource(
authContext,
&testSourceCredential,
sourceModels.RawResourceFhir{
SourceResourceType: "Patient",
SourceResourceID: "b426b062-8273-4b93-a907-de3176c0567d",
ResourceRaw: testPatientData,
},
)
require.NoError(suite.T(), err)
require.True(suite.T(), wasCreated)
//test & assert
findPatientResource, err := dbRepo.GetResourceByResourceTypeAndId(authContext, "Patient", "b426b062-8273-4b93-a907-de3176c0567d")
require.NoError(suite.T(), err)
require.NotNil(suite.T(), findPatientResource)
//raise an error if the resource is not found (invalid resource type or id missing)
_, err = dbRepo.GetResourceByResourceTypeAndId(authContext, "Patient", "11111111-8273-4b93-a907-de3176c0567d")
require.Error(suite.T(), err)
_, err = dbRepo.GetResourceByResourceTypeAndId(authContext, "Observation", "b426b062-8273-4b93-a907-de3176c0567d")
require.Error(suite.T(), err)
_, err = dbRepo.GetResourceByResourceTypeAndId(authContext, "InvalidResource", "b426b062-8273-4b93-a907-de3176c0567d")
require.Error(suite.T(), err)
}
func (suite *RepositoryTestSuite) TestGetResourceBySourceId() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
testPatientData, err := os.ReadFile("./testdata/Abraham100_Heller342_Patient.json")
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
wasCreated, err := dbRepo.UpsertRawResource(
authContext,
&testSourceCredential,
sourceModels.RawResourceFhir{
SourceResourceType: "Patient",
SourceResourceID: "b426b062-8273-4b93-a907-de3176c0567d",
ResourceRaw: testPatientData,
},
)
require.NoError(suite.T(), err)
require.True(suite.T(), wasCreated)
//test & assert
findPatientResource, err := dbRepo.GetResourceBySourceId(authContext, testSourceCredential.ID.String(), "b426b062-8273-4b93-a907-de3176c0567d")
require.NoError(suite.T(), err)
require.NotNil(suite.T(), findPatientResource)
//raise an error if the resource is not found (invalid resource id for source)
_, err = dbRepo.GetResourceByResourceTypeAndId(authContext, testSourceCredential.ID.String(), "11111111-8273-4b93-a907-de3176c0567d")
require.Error(suite.T(), err)
_, err = dbRepo.GetResourceByResourceTypeAndId(authContext, uuid.NewString(), "b426b062-8273-4b93-a907-de3176c0567d")
require.Error(suite.T(), err)
_, err = dbRepo.GetResourceByResourceTypeAndId(authContext, testSourceCredential.ID.String(), "")
require.Error(suite.T(), err)
}
func (suite *RepositoryTestSuite) TestGetPatientForSources() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
testPatientData, err := os.ReadFile("./testdata/Abraham100_Heller342_Patient.json")
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
wasCreated, err := dbRepo.UpsertRawResource(
authContext,
&testSourceCredential,
sourceModels.RawResourceFhir{
SourceResourceType: "Patient",
SourceResourceID: "b426b062-8273-4b93-a907-de3176c0567d",
ResourceRaw: testPatientData,
},
)
require.NoError(suite.T(), err)
require.True(suite.T(), wasCreated)
was2Created, err := dbRepo.UpsertRawResource(
authContext,
&testSourceCredential,
sourceModels.RawResourceFhir{
SourceResourceType: "Patient",
SourceResourceID: "11111111-8273-4b93-a907-de3176c0567d",
ResourceRaw: testPatientData,
},
)
require.NoError(suite.T(), err)
require.True(suite.T(), was2Created)
//test & assert
findPatients, err := dbRepo.GetPatientForSources(authContext)
require.NoError(suite.T(), err)
require.NotNil(suite.T(), findPatients)
require.Len(suite.T(), findPatients, 2) //TODO: this may need to change to 1 if we group by source_id
}
func (suite *RepositoryTestSuite) TestAddResourceAssociation() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
//test
err = dbRepo.AddResourceAssociation(authContext,
&testSourceCredential, "Patient", "b426b062-8273-4b93-a907-de3176c0567d",
&testSourceCredential, "Observation", "11111111-8273-4b93-a907-de3176c0567d")
require.NoError(suite.T(), err)
//assert
related, err := dbRepo.FindResourceAssociationsByTypeAndId(authContext, &testSourceCredential, "Patient", "b426b062-8273-4b93-a907-de3176c0567d")
require.NoError(suite.T(), err)
require.Equal(suite.T(), 1, len(related))
}
func (suite *RepositoryTestSuite) TestAddResourceAssociation_WithMismatchingSourceIds() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
//test 1 - user id does not match the user id on resources (but they match eachother)
differentUserIdSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: uuid.New(),
}
errForUserMismatch := dbRepo.AddResourceAssociation(authContext,
&differentUserIdSourceCredential, "Patient", "b426b062-8273-4b93-a907-de3176c0567d",
&differentUserIdSourceCredential, "Observation", "11111111-8273-4b93-a907-de3176c0567d")
require.Error(suite.T(), errForUserMismatch)
//test 2 - user id for resources do not match eachother
sourceCredential1 := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: uuid.New(),
}
sourceCredential2 := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: uuid.New(),
}
require.NotEqual(suite.T(), sourceCredential1.UserID, sourceCredential2.UserID)
errForResourceMismatch := dbRepo.AddResourceAssociation(authContext,
&sourceCredential1, "Patient", "b426b062-8273-4b93-a907-de3176c0567d",
&sourceCredential2, "Observation", "11111111-8273-4b93-a907-de3176c0567d")
require.Error(suite.T(), errForResourceMismatch)
}
func (suite *RepositoryTestSuite) TestRemoveResourceAssociation() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
err = dbRepo.AddResourceAssociation(authContext,
&testSourceCredential, "Patient", "b426b062-8273-4b93-a907-de3176c0567d",
&testSourceCredential, "Observation", "11111111-8273-4b93-a907-de3176c0567d")
require.NoError(suite.T(), err)
//test
errWhenNotExists := dbRepo.RemoveResourceAssociation(authContext,
&testSourceCredential, "Patient", "999999999-8273-4b93-a907-de3176c0567d",
&testSourceCredential, "Observation", "11111111-8273-4b93-a907-de3176c0567d")
require.Errorf(suite.T(), errWhenNotExists, "association should not exist, so deletion should fail")
err = dbRepo.RemoveResourceAssociation(authContext,
&testSourceCredential, "Patient", "b426b062-8273-4b93-a907-de3176c0567d",
&testSourceCredential, "Observation", "11111111-8273-4b93-a907-de3176c0567d")
require.NoError(suite.T(), err)
}
func (suite *RepositoryTestSuite) TestGetSourceSummary() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
err = dbRepo.CreateSource(authContext, &testSourceCredential)
require.NoError(suite.T(), err)
testPatientData, err := os.ReadFile("./testdata/Abraham100_Heller342_262b819a-5193-404a-9787-b7f599358035.json")
require.NoError(suite.T(), err)
var testPatientBundle fhir401.Bundle
err = json.Unmarshal(testPatientData, &testPatientBundle)
require.NoError(suite.T(), err)
for _, resourceEntry := range testPatientBundle.Entry {
fhirResource, _ := fhirutils.MapToResource(resourceEntry.Resource, false)
resourceType, resourceId := fhirResource.(sourceModels.ResourceInterface).ResourceRef()
if resourceId == nil {
suite.T().Logf("skipping resource with no ID: %s", resourceType)
continue //skip resources missing an ID
}
wasCreated, err := dbRepo.UpsertRawResource(
authContext,
&testSourceCredential,
sourceModels.RawResourceFhir{
SourceResourceType: resourceType,
SourceResourceID: *resourceId,
ResourceRaw: resourceEntry.Resource,
},
)
require.NoError(suite.T(), err)
require.True(suite.T(), wasCreated)
}
//test
sourceSummary, err := dbRepo.GetSourceSummary(authContext, testSourceCredential.ID.String())
require.NoError(suite.T(), err)
require.NotNil(suite.T(), sourceSummary)
//validated using https://www.maxmddirect.com/direct/FHIR/ResponseViewer
require.Equal(suite.T(), []map[string]interface{}{
{"count": int64(1), "resource_type": "CarePlan", "source_id": testSourceCredential.ID.String()},
{"count": int64(1), "resource_type": "CareTeam", "source_id": testSourceCredential.ID.String()},
{"count": int64(22), "resource_type": "Claim", "source_id": testSourceCredential.ID.String()},
{"count": int64(8), "resource_type": "Condition", "source_id": testSourceCredential.ID.String()},
{"count": int64(2), "resource_type": "DiagnosticReport", "source_id": testSourceCredential.ID.String()},
{"count": int64(18), "resource_type": "Encounter", "source_id": testSourceCredential.ID.String()},
{"count": int64(18), "resource_type": "ExplanationOfBenefit", "source_id": testSourceCredential.ID.String()},
{"count": int64(16), "resource_type": "Immunization", "source_id": testSourceCredential.ID.String()},
{"count": int64(4), "resource_type": "MedicationRequest", "source_id": testSourceCredential.ID.String()},
{"count": int64(93), "resource_type": "Observation", "source_id": testSourceCredential.ID.String()},
{"count": int64(3), "resource_type": "Organization", "source_id": testSourceCredential.ID.String()},
{"count": int64(1), "resource_type": "Patient", "source_id": testSourceCredential.ID.String()},
{"count": int64(3), "resource_type": "Practitioner", "source_id": testSourceCredential.ID.String()},
{"count": int64(8), "resource_type": "Procedure", "source_id": testSourceCredential.ID.String()},
}, sourceSummary.ResourceTypeCounts)
require.Equal(suite.T(), "b426b062-8273-4b93-a907-de3176c0567d", sourceSummary.Patient.SourceResourceID)
require.Equal(suite.T(), "Patient", sourceSummary.Patient.SourceResourceType)
require.NotEmpty(suite.T(), sourceSummary.Patient.ResourceRaw)
}
func (suite *RepositoryTestSuite) TestGetSummary() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
testSourceCredential1 := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
Patient: uuid.New().String(),
}
err = dbRepo.CreateSource(authContext, &testSourceCredential1)
require.NoError(suite.T(), err)
testSourceCredential2 := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
Patient: uuid.New().String(),
}
err = dbRepo.CreateSource(authContext, &testSourceCredential2)
require.NoError(suite.T(), err)
testPatientData, err := os.ReadFile("./testdata/Abraham100_Heller342_262b819a-5193-404a-9787-b7f599358035.json")
require.NoError(suite.T(), err)
var testPatientBundle fhir401.Bundle
err = json.Unmarshal(testPatientData, &testPatientBundle)
require.NoError(suite.T(), err)
for _, resourceEntry := range testPatientBundle.Entry {
fhirResource, _ := fhirutils.MapToResource(resourceEntry.Resource, false)
resourceType, resourceId := fhirResource.(sourceModels.ResourceInterface).ResourceRef()
if resourceId == nil {
suite.T().Logf("skipping resource with no ID: %s", resourceType)
continue //skip resources missing an ID
}
wasCreated, err := dbRepo.UpsertRawResource(
authContext,
&testSourceCredential1,
sourceModels.RawResourceFhir{
SourceResourceType: resourceType,
SourceResourceID: *resourceId,
ResourceRaw: resourceEntry.Resource,
},
)
require.NoError(suite.T(), err)
require.True(suite.T(), wasCreated)
wasCreated2, err2 := dbRepo.UpsertRawResource(
authContext,
&testSourceCredential2,
sourceModels.RawResourceFhir{
SourceResourceType: resourceType,
SourceResourceID: *resourceId + "2",
ResourceRaw: resourceEntry.Resource,
},
)
require.NoError(suite.T(), err2)
require.True(suite.T(), wasCreated2)
}
//test
sourceSummary, err := dbRepo.GetSummary(authContext)
require.NoError(suite.T(), err)
require.NotNil(suite.T(), sourceSummary)
//validated using https://www.maxmddirect.com/direct/FHIR/ResponseViewer
require.Equal(suite.T(), []map[string]interface{}{
{"count": int64(2), "resource_type": "CarePlan"},
{"count": int64(2), "resource_type": "CareTeam"},
{"count": int64(44), "resource_type": "Claim"},
{"count": int64(16), "resource_type": "Condition"},
{"count": int64(4), "resource_type": "DiagnosticReport"},
{"count": int64(36), "resource_type": "Encounter"},
{"count": int64(36), "resource_type": "ExplanationOfBenefit"},
{"count": int64(32), "resource_type": "Immunization"},
{"count": int64(8), "resource_type": "MedicationRequest"},
{"count": int64(93 * 2), "resource_type": "Observation"},
{"count": int64(6), "resource_type": "Organization"},
{"count": int64(2), "resource_type": "Patient"},
{"count": int64(6), "resource_type": "Practitioner"},
{"count": int64(16), "resource_type": "Procedure"},
}, sourceSummary.ResourceTypeCounts)
require.Equal(suite.T(), 2, len(sourceSummary.Sources))
require.Equal(suite.T(), 2, len(sourceSummary.Patients))
}
func (suite *RepositoryTestSuite) TestAddResourceComposition() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
Patient: uuid.New().String(),
}
err = dbRepo.CreateSource(authContext, &testSourceCredential)
require.NoError(suite.T(), err)
//test
testCompositionData, err := os.ReadFile("./testdata/Composition_Create.json")
require.NoError(suite.T(), err)
type CompositionPayload struct {
Title string `json:"title"`
Resources []*models.ResourceBase `json:"resources"`
}
var compositionPayload CompositionPayload
err = json.Unmarshal(testCompositionData, &compositionPayload)
require.NoError(suite.T(), err)
//update resources with testSource Credential
for i, _ := range compositionPayload.Resources {
compositionPayload.Resources[i].SourceID = testSourceCredential.ID
}
err = dbRepo.AddResourceComposition(authContext, compositionPayload.Title, compositionPayload.Resources)
require.NoError(suite.T(), err)
//assert
//check that composition was created
compositions, err := dbRepo.ListResources(authContext, models.ListResourceQueryOptions{
SourceID: "00000000-0000-0000-0000-000000000000",
SourceResourceType: "Composition",
})
require.NoError(suite.T(), err)
require.Equal(suite.T(), 1, len(compositions))
//assert that the associations were created
associations, err := dbRepo.FindResourceAssociationsByTypeAndId(authContext,
&models.SourceCredential{UserID: userModel.ID, ModelBase: models.ModelBase{ID: uuid.MustParse("00000000-0000-0000-0000-000000000000")}}, //Compositions have a unique/placeholder credential ID
"Composition", compositions[0].SourceResourceID)
require.NoError(suite.T(), err)
require.Equal(suite.T(), 2, len(associations))
require.Equal(suite.T(), []models.RelatedResource{
{
ResourceBaseUserID: testSourceCredential.UserID,
ResourceBaseSourceID: compositions[0].SourceID,
ResourceBaseSourceResourceType: "Composition",
ResourceBaseSourceResourceID: compositions[0].SourceResourceID,
RelatedResourceUserID: testSourceCredential.UserID,
RelatedResourceSourceID: testSourceCredential.ID,
RelatedResourceSourceResourceType: "Condition",
RelatedResourceSourceResourceID: "bec92fdc-8765-409b-9850-52786d31aa9b",
},
{
ResourceBaseUserID: testSourceCredential.UserID,
ResourceBaseSourceID: compositions[0].SourceID,
ResourceBaseSourceResourceType: "Composition",
ResourceBaseSourceResourceID: compositions[0].SourceResourceID,
RelatedResourceUserID: testSourceCredential.UserID,
RelatedResourceSourceID: testSourceCredential.ID,
RelatedResourceSourceResourceType: "Condition",
RelatedResourceSourceResourceID: "cf39b665-4177-41e3-af34-149421cb895f",
},
}, associations)
}
func (suite *RepositoryTestSuite) TestAddResourceComposition_WithExistingComposition() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.MustParse("00000000-0000-0000-0000-000000000000"),
},
UserID: userModel.ID,
Patient: uuid.New().String(),
}
err = dbRepo.CreateSource(authContext, &testSourceCredential)
require.NoError(suite.T(), err)
//create existing composition
emptyRawJson, err := json.Marshal(map[string]interface{}{})
require.NoError(suite.T(), err)
err = dbRepo.AddResourceComposition(authContext, "existing composition", []*models.ResourceBase{
{
OriginBase: models.OriginBase{
SourceID: testSourceCredential.ID,
SourceResourceType: "Observation",
SourceResourceID: "1",
},
ResourceRaw: emptyRawJson,
},
{
OriginBase: models.OriginBase{
SourceID: testSourceCredential.ID,
SourceResourceType: "Observation",
SourceResourceID: "2",
},
ResourceRaw: emptyRawJson,
},
{
OriginBase: models.OriginBase{
SourceID: testSourceCredential.ID,
SourceResourceType: "Observation",
SourceResourceID: "3",
},
ResourceRaw: emptyRawJson,
},
})
require.NoError(suite.T(), err)
//find existing composition
existingCompositions, err := dbRepo.ListResources(authContext, models.ListResourceQueryOptions{
SourceID: "00000000-0000-0000-0000-000000000000",
SourceResourceType: "Composition",
})
require.NoError(suite.T(), err)
require.Equal(suite.T(), 1, len(existingCompositions), "Only 1 composition should exist at this point")
//test
testCompositionData, err := os.ReadFile("./testdata/Composition_Create.json")
require.NoError(suite.T(), err)
type CompositionPayload struct {
Title string `json:"title"`
Resources []*models.ResourceBase `json:"resources"`
}
var compositionPayload CompositionPayload
err = json.Unmarshal(testCompositionData, &compositionPayload)
require.NoError(suite.T(), err)
//update resources with testSource Credential
for i, _ := range compositionPayload.Resources {
compositionPayload.Resources[i].SourceID = testSourceCredential.ID
}
//add the existing composition as a resource to this composition
compositionPayload.Resources = append(compositionPayload.Resources, &existingCompositions[0])
//test
err = dbRepo.AddResourceComposition(authContext, compositionPayload.Title, compositionPayload.Resources)
require.NoError(suite.T(), err)
//assert
//check that composition was created
compositions, err := dbRepo.ListResources(authContext, models.ListResourceQueryOptions{
SourceID: "00000000-0000-0000-0000-000000000000",
SourceResourceType: "Composition",
})
require.NoError(suite.T(), err)
require.Equal(suite.T(), 1, len(compositions), "Only 1 composition should exist, the previous one should be deleted, and its related resources merged into this one.")
//assert that the associations were created
associations, err := dbRepo.FindResourceAssociationsByTypeAndId(authContext,
&models.SourceCredential{UserID: userModel.ID, ModelBase: models.ModelBase{ID: uuid.MustParse("00000000-0000-0000-0000-000000000000")}}, //Compositions have a unique/placeholder credential ID
"Composition", compositions[0].SourceResourceID)
require.NoError(suite.T(), err)
require.Equal(suite.T(), 5, len(associations))
require.Equal(suite.T(), []models.RelatedResource{
{
ResourceBaseUserID: testSourceCredential.UserID,
ResourceBaseSourceID: compositions[0].SourceID,
ResourceBaseSourceResourceType: "Composition",
ResourceBaseSourceResourceID: compositions[0].SourceResourceID,
RelatedResourceUserID: testSourceCredential.UserID,
RelatedResourceSourceID: testSourceCredential.ID,
RelatedResourceSourceResourceType: "Condition",
RelatedResourceSourceResourceID: "bec92fdc-8765-409b-9850-52786d31aa9b",
},
{
ResourceBaseUserID: testSourceCredential.UserID,
ResourceBaseSourceID: compositions[0].SourceID,
ResourceBaseSourceResourceType: "Composition",
ResourceBaseSourceResourceID: compositions[0].SourceResourceID,
RelatedResourceUserID: testSourceCredential.UserID,
RelatedResourceSourceID: testSourceCredential.ID,
RelatedResourceSourceResourceType: "Condition",
RelatedResourceSourceResourceID: "cf39b665-4177-41e3-af34-149421cb895f",
},
{
ResourceBaseUserID: testSourceCredential.UserID,
ResourceBaseSourceID: compositions[0].SourceID,
ResourceBaseSourceResourceType: "Composition",
ResourceBaseSourceResourceID: compositions[0].SourceResourceID,
RelatedResourceUserID: testSourceCredential.UserID,
RelatedResourceSourceID: testSourceCredential.ID,
RelatedResourceSourceResourceType: "Observation",
RelatedResourceSourceResourceID: "1",
},
{
ResourceBaseUserID: testSourceCredential.UserID,
ResourceBaseSourceID: compositions[0].SourceID,
ResourceBaseSourceResourceType: "Composition",
ResourceBaseSourceResourceID: compositions[0].SourceResourceID,
RelatedResourceUserID: testSourceCredential.UserID,
RelatedResourceSourceID: testSourceCredential.ID,
RelatedResourceSourceResourceType: "Observation",
RelatedResourceSourceResourceID: "2",
},
{
ResourceBaseUserID: testSourceCredential.UserID,
ResourceBaseSourceID: compositions[0].SourceID,
ResourceBaseSourceResourceType: "Composition",
ResourceBaseSourceResourceID: compositions[0].SourceResourceID,
RelatedResourceUserID: testSourceCredential.UserID,
RelatedResourceSourceID: testSourceCredential.ID,
RelatedResourceSourceResourceType: "Observation",
RelatedResourceSourceResourceID: "3",
},
}, associations)
}
func (suite *RepositoryTestSuite) TestCreateBackgroundJob_Sync() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
//test
sourceCredential := models.SourceCredential{ModelBase: models.ModelBase{ID: uuid.New()}, SourceType: sourcePkg.SourceType("bluebutton")}
backgroundJob := models.NewSyncBackgroundJob(sourceCredential)
err = dbRepo.CreateBackgroundJob(
context.WithValue(authContext, pkg.ContextKeyTypeAuthUsername, "test_username"),
backgroundJob,
)
//assert
require.NoError(suite.T(), err)
require.NotEqual(suite.T(), uuid.Nil, backgroundJob.ID)
require.Equal(suite.T(), pkg.BackgroundJobTypeSync, backgroundJob.JobType)
require.Equal(suite.T(), pkg.BackgroundJobStatusLocked, backgroundJob.JobStatus)
require.NotNil(suite.T(), backgroundJob.LockedTime)
require.Nil(suite.T(), backgroundJob.DoneTime)
require.Equal(suite.T(), userModel.ID, backgroundJob.UserID)
}
func (suite *RepositoryTestSuite) TestListBackgroundJobs() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
otherUserModel := &models.User{
Username: "test_other_username",
Password: "testpassword",
Email: "testother@test.com",
}
err = dbRepo.CreateUser(context.Background(), otherUserModel)
require.NoError(suite.T(), err)
testSourceCredential := models.SourceCredential{
ModelBase: models.ModelBase{
ID: uuid.New(),
},
UserID: userModel.ID,
}
backgroundJob := models.NewSyncBackgroundJob(testSourceCredential)
err = dbRepo.CreateBackgroundJob(
context.WithValue(authContext, pkg.ContextKeyTypeAuthUsername, "test_username"),
backgroundJob,
)
backgroundJob2 := models.NewSyncBackgroundJob(testSourceCredential)
backgroundJob2.JobType = pkg.BackgroundJobTypeScheduledSync
err = dbRepo.CreateBackgroundJob(
context.WithValue(authContext, pkg.ContextKeyTypeAuthUsername, "test_username"),
backgroundJob2,
)
backgroundJob3 := models.NewSyncBackgroundJob(testSourceCredential)
backgroundJob3.JobStatus = pkg.BackgroundJobStatusFailed
err = dbRepo.CreateBackgroundJob(
context.WithValue(authContext, pkg.ContextKeyTypeAuthUsername, "test_username"),
backgroundJob3,
)
require.NoError(suite.T(), err)
//test
foundAllBackgroundJobs, err := dbRepo.ListBackgroundJobs(authContext, models.BackgroundJobQueryOptions{})
require.NoError(suite.T(), err)
syncJobType := pkg.BackgroundJobTypeSync
foundBackgroundJobsByType, err := dbRepo.ListBackgroundJobs(authContext, models.BackgroundJobQueryOptions{
JobType: &syncJobType,
})
require.NoError(suite.T(), err)
syncFailedStatus := pkg.BackgroundJobStatusFailed
foundBackgroundJobsByStatus, err := dbRepo.ListBackgroundJobs(authContext, models.BackgroundJobQueryOptions{
Status: &syncFailedStatus,
})
require.NoError(suite.T(), err)
//assert
require.Equal(suite.T(), len(foundAllBackgroundJobs), 3)
require.Equal(suite.T(), len(foundBackgroundJobsByType), 2)
require.Equal(suite.T(), len(foundBackgroundJobsByStatus), 1)
}
func (suite *RepositoryTestSuite) TestUpdateBackgroundJob() {
//setup
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
require.NoError(suite.T(), err)
userModel := &models.User{
Username: "test_username",
Password: "testpassword",
Email: "test@test.com",
}
err = dbRepo.CreateUser(context.Background(), userModel)
require.NoError(suite.T(), err)
authContext := context.WithValue(context.Background(), pkg.ContextKeyTypeAuthUsername, "test_username")
sourceCredential := models.SourceCredential{ModelBase: models.ModelBase{ID: uuid.New()}, SourceType: sourcePkg.SourceType("bluebutton")}
backgroundJob := models.NewSyncBackgroundJob(sourceCredential)
err = dbRepo.CreateBackgroundJob(
context.WithValue(authContext, pkg.ContextKeyTypeAuthUsername, "test_username"),
backgroundJob,
)
//test
now := time.Now()
backgroundJob.JobStatus = pkg.BackgroundJobStatusFailed
backgroundJob.DoneTime = &now
err = dbRepo.UpdateBackgroundJob(
authContext,
backgroundJob,
)
require.NoError(suite.T(), err)
//list all records and ensure that the updated record is the same
foundAllBackgroundJobs, err := dbRepo.ListBackgroundJobs(authContext, models.BackgroundJobQueryOptions{})
require.NoError(suite.T(), err)
//assert
require.Equal(suite.T(), 1, len(foundAllBackgroundJobs))
require.Equal(suite.T(), backgroundJob.ID, foundAllBackgroundJobs[0].ID)
require.Equal(suite.T(), pkg.BackgroundJobStatusFailed, foundAllBackgroundJobs[0].JobStatus)
require.NotNil(suite.T(), foundAllBackgroundJobs[0].DoneTime)
}