2018-02-12 17:29:03 +01:00
|
|
|
package database
|
|
|
|
|
2018-02-13 17:11:22 +01:00
|
|
|
import (
|
2018-09-06 15:34:56 +02:00
|
|
|
"database/sql"
|
2018-02-13 17:11:22 +01:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
2022-05-06 13:05:24 +02:00
|
|
|
"github.com/upper/db/v4"
|
2018-02-13 17:11:22 +01:00
|
|
|
)
|
2018-02-12 17:29:03 +01:00
|
|
|
|
2018-09-07 15:16:20 +02:00
|
|
|
// ResultNetwork is used to represent the structure made from the JOIN
|
|
|
|
// between the results and networks tables.
|
|
|
|
type ResultNetwork struct {
|
2022-01-14 11:24:43 +01:00
|
|
|
Result `db:",inline"`
|
|
|
|
Network `db:",inline"`
|
|
|
|
AnomalyCount uint64 `db:"anomaly_count"`
|
|
|
|
TotalCount uint64 `db:"total_count"`
|
|
|
|
TestKeys string `db:"test_keys"`
|
2018-09-07 15:16:20 +02:00
|
|
|
}
|
|
|
|
|
2021-04-30 17:08:16 +02:00
|
|
|
// UploadedTotalCount is the count of the measurements which have been uploaded vs the total measurements in a given result set
|
|
|
|
type UploadedTotalCount struct {
|
|
|
|
UploadedCount int64 `db:",inline"`
|
|
|
|
TotalCount int64 `db:",inline"`
|
|
|
|
}
|
|
|
|
|
2018-09-07 15:16:20 +02:00
|
|
|
// MeasurementURLNetwork is used for the JOIN between Measurement and URL
|
|
|
|
type MeasurementURLNetwork struct {
|
2018-09-17 17:30:38 +02:00
|
|
|
Measurement `db:",inline"`
|
|
|
|
Network `db:",inline"`
|
|
|
|
Result `db:",inline"`
|
|
|
|
URL `db:",inline"`
|
2018-09-07 15:16:20 +02:00
|
|
|
}
|
|
|
|
|
2018-09-05 18:40:37 +02:00
|
|
|
// Network represents a network tested by the user
|
|
|
|
type Network struct {
|
2018-09-17 17:30:38 +02:00
|
|
|
ID int64 `db:"network_id,omitempty"`
|
2018-09-05 18:40:37 +02:00
|
|
|
NetworkName string `db:"network_name"`
|
2018-09-07 14:06:08 +02:00
|
|
|
NetworkType string `db:"network_type"`
|
2018-09-05 18:40:37 +02:00
|
|
|
IP string `db:"ip"`
|
2018-09-06 16:13:04 +02:00
|
|
|
ASN uint `db:"asn"`
|
2018-09-17 17:30:38 +02:00
|
|
|
CountryCode string `db:"network_country_code"`
|
2018-03-19 16:23:30 +01:00
|
|
|
}
|
|
|
|
|
2018-09-06 16:13:04 +02:00
|
|
|
// URL represents URLs from the testing lists
|
2018-09-05 18:40:37 +02:00
|
|
|
type URL struct {
|
2018-09-17 17:30:38 +02:00
|
|
|
ID sql.NullInt64 `db:"url_id,omitempty"`
|
2018-09-07 15:16:20 +02:00
|
|
|
URL sql.NullString `db:"url"`
|
|
|
|
CategoryCode sql.NullString `db:"category_code"`
|
2018-09-17 17:30:38 +02:00
|
|
|
CountryCode sql.NullString `db:"url_country_code"`
|
2018-06-22 12:12:35 +02:00
|
|
|
}
|
|
|
|
|
2018-02-12 17:29:03 +01:00
|
|
|
// Measurement model
|
|
|
|
type Measurement struct {
|
2018-09-17 17:30:38 +02:00
|
|
|
ID int64 `db:"measurement_id,omitempty"`
|
2018-09-06 15:34:56 +02:00
|
|
|
TestName string `db:"test_name"`
|
2018-09-17 17:30:38 +02:00
|
|
|
StartTime time.Time `db:"measurement_start_time"`
|
|
|
|
Runtime float64 `db:"measurement_runtime"` // Fractional number of seconds
|
|
|
|
IsDone bool `db:"measurement_is_done"`
|
|
|
|
IsUploaded bool `db:"measurement_is_uploaded"`
|
|
|
|
IsFailed bool `db:"measurement_is_failed"`
|
|
|
|
FailureMsg sql.NullString `db:"measurement_failure_msg,omitempty"`
|
|
|
|
IsUploadFailed bool `db:"measurement_is_upload_failed"`
|
|
|
|
UploadFailureMsg sql.NullString `db:"measurement_upload_failure_msg,omitempty"`
|
|
|
|
IsRerun bool `db:"measurement_is_rerun"`
|
2018-09-06 15:34:56 +02:00
|
|
|
ReportID sql.NullString `db:"report_id,omitempty"`
|
2018-09-07 12:55:27 +02:00
|
|
|
URLID sql.NullInt64 `db:"url_id,omitempty"` // Used to reference URL
|
2018-09-17 17:30:38 +02:00
|
|
|
MeasurementID sql.NullInt64 `db:"collector_measurement_id,omitempty"`
|
2018-09-06 15:34:56 +02:00
|
|
|
IsAnomaly sql.NullBool `db:"is_anomaly,omitempty"`
|
|
|
|
// FIXME we likely want to support JSON. See: https://github.com/upper/db/issues/462
|
2020-01-28 11:53:00 +01:00
|
|
|
TestKeys string `db:"test_keys"`
|
|
|
|
ResultID int64 `db:"result_id"`
|
|
|
|
ReportFilePath sql.NullString `db:"report_file_path,omitempty"`
|
|
|
|
MeasurementFilePath sql.NullString `db:"measurement_file_path,omitempty"`
|
2018-09-05 18:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Result model
|
|
|
|
type Result struct {
|
2018-09-17 17:30:38 +02:00
|
|
|
ID int64 `db:"result_id,omitempty"`
|
2018-09-05 18:40:37 +02:00
|
|
|
TestGroupName string `db:"test_group_name"`
|
2018-09-17 17:30:38 +02:00
|
|
|
StartTime time.Time `db:"result_start_time"`
|
|
|
|
NetworkID int64 `db:"network_id"` // Used to include a Network
|
|
|
|
Runtime float64 `db:"result_runtime"` // Runtime is expressed in fractional seconds
|
|
|
|
IsViewed bool `db:"result_is_viewed"`
|
|
|
|
IsDone bool `db:"result_is_done"`
|
2021-04-30 17:08:16 +02:00
|
|
|
IsUploaded bool `db:"result_is_uploaded"`
|
2018-09-17 17:30:38 +02:00
|
|
|
DataUsageUp float64 `db:"result_data_usage_up"`
|
|
|
|
DataUsageDown float64 `db:"result_data_usage_down"`
|
2018-09-05 18:40:37 +02:00
|
|
|
MeasurementDir string `db:"measurement_dir"`
|
|
|
|
}
|
|
|
|
|
2018-09-11 18:41:15 +02:00
|
|
|
// PerformanceTestKeys is the result summary for a performance test
|
|
|
|
type PerformanceTestKeys struct {
|
|
|
|
Upload float64 `json:"upload"`
|
|
|
|
Download float64 `json:"download"`
|
|
|
|
Ping float64 `json:"ping"`
|
|
|
|
Bitrate float64 `json:"median_bitrate"`
|
|
|
|
}
|
|
|
|
|
2018-09-05 18:40:37 +02:00
|
|
|
// Finished marks the result as done and sets the runtime
|
2022-05-06 13:05:24 +02:00
|
|
|
func (r *Result) Finished(sess db.Session) error {
|
2022-11-15 10:35:30 +01:00
|
|
|
if r.IsDone || r.Runtime != 0 {
|
2018-09-05 18:40:37 +02:00
|
|
|
return errors.New("Result is already finished")
|
|
|
|
}
|
|
|
|
r.Runtime = time.Now().UTC().Sub(r.StartTime).Seconds()
|
|
|
|
r.IsDone = true
|
|
|
|
|
2018-09-17 17:30:38 +02:00
|
|
|
err := sess.Collection("results").Find("result_id", r.ID).Update(r)
|
2018-09-05 18:40:37 +02:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "updating finished result")
|
|
|
|
}
|
|
|
|
return nil
|
2018-02-13 17:11:22 +01:00
|
|
|
}
|
|
|
|
|
2018-03-19 16:23:30 +01:00
|
|
|
// Failed writes the error string to the measurement
|
2022-05-06 13:05:24 +02:00
|
|
|
func (m *Measurement) Failed(sess db.Session, failure string) error {
|
2018-09-06 15:34:56 +02:00
|
|
|
m.FailureMsg = sql.NullString{String: failure, Valid: true}
|
2018-09-11 15:19:08 +02:00
|
|
|
m.IsFailed = true
|
2018-09-17 17:30:38 +02:00
|
|
|
err := sess.Collection("measurements").Find("measurement_id", m.ID).Update(m)
|
2018-03-19 16:23:30 +01:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "updating measurement")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Done marks the measurement as completed
|
2022-05-06 13:05:24 +02:00
|
|
|
func (m *Measurement) Done(sess db.Session) error {
|
2018-03-20 12:38:33 +01:00
|
|
|
runtime := time.Now().UTC().Sub(m.StartTime)
|
|
|
|
m.Runtime = runtime.Seconds()
|
2018-09-05 18:40:37 +02:00
|
|
|
m.IsDone = true
|
2018-03-19 16:23:30 +01:00
|
|
|
|
2018-09-17 17:30:38 +02:00
|
|
|
err := sess.Collection("measurements").Find("measurement_id", m.ID).Update(m)
|
2018-03-19 16:23:30 +01:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "updating measurement")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UploadFailed writes the error string for the upload failure to the measurement
|
2022-05-06 13:05:24 +02:00
|
|
|
func (m *Measurement) UploadFailed(sess db.Session, failure string) error {
|
2018-09-06 15:34:56 +02:00
|
|
|
m.UploadFailureMsg = sql.NullString{String: failure, Valid: true}
|
2018-09-05 18:40:37 +02:00
|
|
|
m.IsUploaded = false
|
2018-03-19 16:23:30 +01:00
|
|
|
|
2018-09-17 17:30:38 +02:00
|
|
|
err := sess.Collection("measurements").Find("measurement_id", m.ID).Update(m)
|
2018-03-19 16:23:30 +01:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "updating measurement")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UploadSucceeded writes the error string for the upload failure to the measurement
|
2022-05-06 13:05:24 +02:00
|
|
|
func (m *Measurement) UploadSucceeded(sess db.Session) error {
|
2018-09-05 18:40:37 +02:00
|
|
|
m.IsUploaded = true
|
2018-03-19 16:23:30 +01:00
|
|
|
|
2018-09-17 17:30:38 +02:00
|
|
|
err := sess.Collection("measurements").Find("measurement_id", m.ID).Update(m)
|
2018-03-19 16:23:30 +01:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "updating measurement")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|