package repository_test import ( "bytes" "context" "encoding/json" "fmt" "math/rand" "net/url" "os" "path/filepath" "testing" "time" "git.cryptic.systems/volker.raschek/flucky/pkg/repository" "git.cryptic.systems/volker.raschek/flucky/pkg/testutils/dockerutils" "git.cryptic.systems/volker.raschek/flucky/pkg/types" "git.cryptic.systems/volker.raschek/go-logger" uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/require" _ "github.com/lib/pq" _ "github.com/mattn/go-sqlite3" ) func TestPostgresBackend(t *testing.T) { require := require.New(t) dockerClient, err := dockerutils.New() require.NoError(err) rand.Seed(time.Now().Unix()) postgresHostPort := rand.Intn(10024-1024) + 1024 postgresDBPasswort := "postgres" postgresContainerID, err := dockerClient.NewBuilder("postgres:13-alpine"). Port(fmt.Sprintf("%v:5432/tcp", postgresHostPort)). Pull(). AddEnv("PGTZ", "Europe/Berlin"). AddEnv("POSTGRES_PASSWORD", postgresDBPasswort). AddEnv("TZ", "Europe/Berlin"). Mount("/etc/localtime", "/etc/localtime"). Start(context.Background()) cleanup := func() { dockerClient.ContainerRemoveByIDs(context.Background(), postgresContainerID) } t.Cleanup(cleanup) require.NoError(err) time.Sleep(time.Second * 10) // postgres://[user]:[password]@[host]:[port]/[path]?[query] dsnURL, err := url.Parse(fmt.Sprintf("postgres://postgres:%v@127.0.0.1:%v?sslmode=disable", postgresDBPasswort, postgresHostPort)) require.NoError(err) repo, err := repository.New(dsnURL, logger.NewLogger(logger.LogLevelDebug)) require.NoError(err) testBackend(t, repo) } func TestSQLiteBackend(t *testing.T) { require := require.New(t) workspace := filepath.Join(os.TempDir(), uuid.NewV4().String()) err := os.MkdirAll(workspace, 0755) require.NoError(err) t.Cleanup(func() { os.RemoveAll(workspace) }) dsnURL, err := url.Parse(fmt.Sprintf("sqlite3://%v/test.db", workspace)) require.NoError(err) repo, err := repository.New(dsnURL, logger.NewLogger(logger.LogLevelDebug)) require.NoError(err) testBackend(t, repo) } func testBackend(t *testing.T, repo *repository.Repository) { require := require.New(t) location := uuid.NewV4().String() expectedDevices := []*types.Device{ { ID: "39b8f150-8abf-4539-9f16-7f68cedb1649", Name: "62e3978f-2198-4aa9-9d6f-cdc91a468b00", Location: &location, CreationDate: *timeNow(require), }, { ID: "ec0be3ab-d26d-4f9b-a96e-23ae5c577f8f", Name: "f2b245eb-b15f-40e1-9212-9a645907b710", Location: &location, CreationDate: *timeNow(require), }, } // Test: AddDevice err := repo.AddDevices(expectedDevices...) require.NoError(err) // Test: GetDevices devices, err := repo.GetDevices() require.NoError(err) require.Len(devices, len(expectedDevices)) require.JSONEq(jsonEncoder(expectedDevices), jsonEncoder(devices)) // Test: GetDevice device, err := repo.GetDevice(expectedDevices[0].ID) require.NoError(err) require.JSONEq(jsonEncoder(expectedDevices[0]), jsonEncoder(device)) // Test: RemoveDevice err = repo.RemoveDevices(expectedDevices[0].ID) require.NoError(err) devices, err = repo.GetDevices() require.NoError(err) require.Len(devices, 1) device, err = repo.GetDevice(expectedDevices[0].ID) require.NoError(err) require.Nil(device) err = repo.AddDevices(expectedDevices[0]) require.NoError(err) // Test: Update Devices location = "MyLocation" expectedDevice := &types.Device{ ID: "ec0be3ab-d26d-4f9b-a96e-23ae5c577f8f", Name: "Hello World", Location: &location, CreationDate: *timeNow(require), } err = repo.UpdateDevices(expectedDevice) require.NoError(err) device, err = repo.GetDevice(expectedDevice.ID) require.NoError(err) // require.JSONEq(jsonEncoder(expectedDevice), jsonEncoder(device)) var ( wireID = "50473fdc-f6ef-4227-b3c4-484d8e9c1323" i2cBus = 1 i2cAddress uint8 = 76 expectedSensors = []*types.Sensor{ { ID: "0f8b88b0-c20d-42b2-ab51-b09ca99c0752", Name: "e1fbdbe9-cebf-42ed-8065-bf4882ccf76b", Location: "6d5b5450-1f87-47cb-b185-f64c35fae3c1", GPIONumber: "GPIO14", Model: "DHT11", Enabled: true, TickDuration: "1m", DeviceID: "ec0be3ab-d26d-4f9b-a96e-23ae5c577f8f", CreationDate: *timeNow(require), }, { ID: "80b1c4bd-abec-4ff0-afb4-bd70aeed0c83", Name: "544365ee-ece9-44ea-911d-5d920a68d4ba", Location: "7ae2d05e-9e6b-4d2d-b26a-cb4acca83778", WireID: &wireID, Model: "DS18B20", Enabled: true, TickDuration: "5m", DeviceID: "ec0be3ab-d26d-4f9b-a96e-23ae5c577f8f", CreationDate: *timeNow(require), }, { ID: "8c74397f-8e60-4c9d-960d-3197747cef9a", Name: "4b808675-de02-4866-893d-1c77f23b9304", Location: "8a085c0f-dd3c-447f-8c4e-c4c1d869c7b6", I2CBus: &i2cBus, I2CAddress: &i2cAddress, Model: "BME280", Enabled: false, TickDuration: "10m", DeviceID: "39b8f150-8abf-4539-9f16-7f68cedb1649", CreationDate: *timeNow(require), }, } ) // Test: AddSensors err = repo.AddSensors(expectedSensors...) require.NoError(err) // Test: GetSensors sensors, err := repo.GetSensors() require.NoError(err) require.Len(sensors, len(expectedSensors)) sensors, err = repo.GetSensors("BME280") require.NoError(err) require.Len(sensors, 1) require.JSONEq(jsonEncoder(expectedSensors[2]), jsonEncoder(sensors[0])) sensors, err = repo.GetSensors("DS18B20") require.NoError(err) require.Len(sensors, 1) require.JSONEq(jsonEncoder(expectedSensors[1]), jsonEncoder(sensors[0])) sensors, err = repo.GetSensors("DHT11") require.NoError(err) require.Len(sensors, 1) require.JSONEq(jsonEncoder(expectedSensors[0]), jsonEncoder(sensors[0])) sensors, err = repo.GetSensors("DHT11", "DS18B20") require.NoError(err) require.Len(sensors, 2) require.ElementsMatch(expectedSensors[0:2], sensors) // Test: GetSensor sensor, err := repo.GetSensor(expectedSensors[0].ID) require.NoError(err) require.JSONEq(jsonEncoder(expectedSensors[0]), jsonEncoder(sensor)) // Test: GetSensorsByDeviceID sensors, err = repo.GetSensorsByDeviceID("ec0be3ab-d26d-4f9b-a96e-23ae5c577f8f") require.NoError(err) require.Len(sensors, 2) require.JSONEq(jsonEncoder(expectedSensors[0:2]), jsonEncoder(sensors)) // Test: RemoveSensors err = repo.RemoveSensors(expectedSensors[0].ID) require.NoError(err) sensors, err = repo.GetSensors() require.NoError(err) require.Len(sensors, 2) sensors, err = repo.GetSensorsByDeviceID("ec0be3ab-d26d-4f9b-a96e-23ae5c577f8f") require.NoError(err) require.Len(sensors, 1) sensor, err = repo.GetSensor(expectedSensors[0].ID) require.NoError(err) require.Nil(sensor) // Test: RemoveSensorsByNames err = repo.RemoveSensorsByNames(expectedSensors[1].Name) require.NoError(err) sensors, err = repo.GetSensors() require.NoError(err) require.Len(sensors, 1) sensor, err = repo.GetSensor(expectedSensors[1].ID) require.NoError(err) require.Nil(sensor) // Test: RenameSensor err = repo.RenameSensors(expectedSensors[2].Name, "Hello") require.NoError(err) sensor, err = repo.GetSensor(expectedSensors[2].ID) require.Equal("Hello", sensor.Name) require.NotNil(sensor) // Test: DisableSensorsByNames err = repo.DisableSensorsByNames("Hello") require.NoError(err) sensor, err = repo.GetSensor(expectedSensors[2].ID) require.False(sensor.Enabled) require.NotNil(sensor) // Test: EnableSensorsByName err = repo.EnableSensorsByNames("Hello") require.NoError(err) sensor, err = repo.GetSensor(expectedSensors[2].ID) require.True(sensor.Enabled) require.NotNil(sensor) // Test: UpdateSensors expectedSensor := &types.Sensor{ ID: "8c74397f-8e60-4c9d-960d-3197747cef9a", Name: "4b808675-de02-4866-893d-1c77f23b9304", Location: "Über den Wolken muss die Freiheit wohl grenzenlos sein...", I2CBus: nil, I2CAddress: nil, Model: "SDS011", Enabled: true, TickDuration: "6h", DeviceID: "39b8f150-8abf-4539-9f16-7f68cedb1649", CreationDate: *timeNow(require), } err = repo.UpdateSensors(expectedSensor) require.NoError(err) sensor, err = repo.GetSensor(expectedSensor.ID) require.NoError(err) require.NotNil(sensor) // require.JSONEq(jsonEncoder(expectedSensor), jsonEncoder(sensor)) var ( expectedMeasuredValues = []*types.MeasuredValue{ { ID: "2e5a297a-3da0-46ae-89d2-0fcab0f1d5f7", Value: 32, ValueType: types.Humidity, Date: *timeNow(require), SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a", CreationDate: *timeNow(require), UpdateDate: nil, }, { ID: "d69f1b62-0c6c-4058-b42c-4a2821bd220c", Value: 38, ValueType: types.Pressure, Date: *timeNow(require), SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a", CreationDate: *timeNow(require), UpdateDate: nil, }, { ID: "ea945ae0-412b-4561-a191-1f8f1f909fa4", Value: 35.4, ValueType: types.Temperature, Date: *timeNow(require), SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a", CreationDate: *timeNow(require), UpdateDate: nil, }, } ) // Test: AddMeasuredValues err = repo.AddMeasuredValues(expectedMeasuredValues...) require.NoError(err) } func jsonEncoder(v interface{}) string { body := make([]byte, 0) buffer := bytes.NewBuffer(body) jsonEncoder := json.NewEncoder(buffer) jsonEncoder.SetIndent("", " ") jsonEncoder.Encode(v) return buffer.String() } func timeNow(require *require.Assertions) *time.Time { now, err := time.Parse("2006-01-02 15:04:05.999999Z", time.Now().Format("2006-01-02 15:04:05.999999Z")) require.NoError(err) return &now }