api/handlers_test.go
package api
import (
"database/sql"
"encoding/hex"
"encoding/json"
"fmt"
"math"
"testing"
"time"
"github.com/stretchr/testify/suite"
"github.com/volatiletech/null/v8"
"github.com/volatiletech/sqlboiler/v4/boil"
"github.com/Bnei-Baruch/mdb/common"
"github.com/Bnei-Baruch/mdb/models"
"github.com/Bnei-Baruch/mdb/utils"
)
type HandlersSuite struct {
suite.Suite
utils.TestDBManager
tx *sql.Tx
}
func (suite *HandlersSuite) SetupSuite() {
suite.Require().Nil(suite.InitTestDB())
suite.Require().Nil(common.InitTypeRegistries(suite.DB))
}
func (suite *HandlersSuite) TearDownSuite() {
suite.Require().Nil(suite.DestroyTestDB())
}
func (suite *HandlersSuite) SetupTest() {
var err error
suite.tx, err = suite.DB.Begin()
suite.Require().Nil(err)
}
func (suite *HandlersSuite) TearDownTest() {
err := suite.tx.Rollback()
suite.Require().Nil(err)
}
// 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 TestHandlers(t *testing.T) {
suite.Run(t, new(HandlersSuite))
}
func (suite *HandlersSuite) TestHandleCaptureStart() {
input := CaptureStartRequest{
Operation: Operation{
Station: "Capture station",
User: "operator@dev.com",
WorkflowID: "c12356789",
},
FileName: "heb_o_rav_rb-1990-02-kishalon_2016-09-14_lesson.mp4",
CaptureSource: "mltcap",
CollectionUID: "abcdefgh",
}
op, evnts, err := handleCaptureStart(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_CAPTURE_START].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"], "properties: workflow_id")
suite.Equal(input.CaptureSource, props["capture_source"], "properties: capture_source")
suite.Equal(input.CollectionUID, props["collection_uid"], "properties: collection_uid")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
f := op.R.Files[0]
suite.Equal(input.FileName, f.Name, "File: Name")
suite.False(f.Sha1.Valid, "File: SHA1")
}
func (suite *HandlersSuite) TestHandleCaptureStop() {
// Prepare capture_start operation
opStart, evnts, err := handleCaptureStart(suite.tx, CaptureStartRequest{
Operation: Operation{
Station: "Capture station",
User: "operator@dev.com",
WorkflowID: "c12356789",
},
FileName: "heb_o_rav_rb-1990-02-kishalon_2016-09-14_lesson.mp4",
CaptureSource: "mltcap",
CollectionUID: "abcdefgh",
})
suite.Require().Nil(err)
suite.Require().Nil(evnts)
suite.Require().Nil(opStart.L.LoadFiles(suite.tx, true, opStart, nil))
parent := opStart.R.Files[0]
// Do capture_stop operation
input := CaptureStopRequest{
Operation: Operation{
Station: "Capture station",
User: "operator@dev.com",
WorkflowID: "c12356789",
},
File: File{
FileName: "heb_o_rav_rb-1990-02-kishalon_2016-09-14_lesson.mp4",
Sha1: "012356789abcdef012356789abcdef0123456789",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
Type: "type",
SubType: "subtype",
MimeType: "mime_type",
Language: common.LANG_MULTI,
},
CaptureSource: "mltcap",
CollectionUID: "abcdefgh",
Part: "part",
LabelID: null.IntFrom(123),
}
op, evnts, err := handleCaptureStop(suite.tx, input)
suite.Require().Nil(err)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_CAPTURE_STOP].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"], "properties: workflow_id")
suite.Equal(input.CaptureSource, props["capture_source"], "properties: capture_source")
suite.Equal(input.CollectionUID, props["collection_uid"], "properties: collection_uid")
suite.Equal(input.Part, props["part"], "properties: part")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
f := op.R.Files[0]
suite.Equal(input.FileName, f.Name, "File: Name")
suite.Equal(input.Sha1, hex.EncodeToString(f.Sha1.Bytes), "File: SHA1")
suite.Equal(input.Size, f.Size, "File: Size")
suite.Equal(input.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "File: FileCreatedAt")
suite.Equal(parent.ID, f.ParentID.Int64, "File Parent.ID")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.LabelID.Int, int(props["label_id"].(float64)), "file properties: label_id")
}
func (suite *HandlersSuite) TestHandleDemux() {
// Create dummy parent file
fi := File{
FileName: "dummy parent file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef0123456789",
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, fi, nil)
suite.Require().Nil(err)
// Do demux operation
input := DemuxRequest{
Operation: Operation{
Station: "Trimmer station",
User: "operator@dev.com",
},
Sha1: fi.Sha1,
Original: AVFile{
File: File{
FileName: "original.mp4",
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 892.1900,
},
Proxy: &AVFile{
File: File{
FileName: "proxy.mp4",
Sha1: "987653210abcdef012356789abcdef9876543210",
Size: 987,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 891.8800,
},
CaptureSource: "mltcap",
}
op, evnts, err := handleDemux(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_DEMUX].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.CaptureSource, props["capture_source"], "properties: capture_source")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 3, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
parent := fm[fi.FileName]
// Check original
original := fm[input.Original.FileName]
suite.Equal(input.Original.FileName, original.Name, "Original: Name")
suite.Equal(input.Original.Sha1, hex.EncodeToString(original.Sha1.Bytes), "Original: SHA1")
suite.Equal(input.Original.Size, original.Size, "Original: Size")
suite.Equal(input.Original.CreatedAt.Time.Unix(), original.FileCreatedAt.Time.Unix(), "Original: FileCreatedAt")
suite.Equal(parent.ID, original.ParentID.Int64, "Original Parent.ID")
err = original.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Original.Duration, props["duration"], "Original props: duration")
// Check proxy
proxy := fm[input.Proxy.FileName]
suite.Equal(input.Proxy.FileName, proxy.Name, "Proxy: Name")
suite.Equal(input.Proxy.Sha1, hex.EncodeToString(proxy.Sha1.Bytes), "Proxy: SHA1")
suite.Equal(input.Proxy.Size, proxy.Size, "Proxy: Size")
suite.Equal(input.Proxy.CreatedAt.Time.Unix(), proxy.FileCreatedAt.Time.Unix(), "Proxy: FileCreatedAt")
suite.Equal(parent.ID, proxy.ParentID.Int64, "Proxy Parent.ID")
err = proxy.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Proxy.Duration, props["duration"], "Proxy props: duration")
}
func (suite *HandlersSuite) TestHandleDemuxNoProxy() {
// Create dummy parent file
fi := File{
FileName: "dummy parent file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef0123456789",
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, fi, nil)
suite.Require().Nil(err)
// Do demux operation
input := DemuxRequest{
Operation: Operation{
Station: "Trimmer station",
User: "operator@dev.com",
},
Sha1: fi.Sha1,
Original: AVFile{
File: File{
FileName: "original.mp4",
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 892.1900,
},
CaptureSource: "capture_without_proxy",
}
op, evnts, err := handleDemux(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_DEMUX].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.CaptureSource, props["capture_source"], "properties: capture_source")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 2, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
parent := fm[fi.FileName]
// Check original
original := fm[input.Original.FileName]
suite.Equal(input.Original.FileName, original.Name, "Original: Name")
suite.Equal(input.Original.Sha1, hex.EncodeToString(original.Sha1.Bytes), "Original: SHA1")
suite.Equal(input.Original.Size, original.Size, "Original: Size")
suite.Equal(input.Original.CreatedAt.Time.Unix(), original.FileCreatedAt.Time.Unix(), "Original: FileCreatedAt")
suite.Equal(parent.ID, original.ParentID.Int64, "Original Parent.ID")
err = original.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Original.Duration, props["duration"], "Original props: duration")
}
func (suite *HandlersSuite) TestHandleTrim() {
// Create dummy original and proxy parent files
ofi := File{
FileName: "dummy original parent file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, ofi, nil)
suite.Require().Nil(err)
pfi := File{
FileName: "dummy proxy parent file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "987653210abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
_, err = CreateFile(suite.tx, nil, pfi, nil)
suite.Require().Nil(err)
// Do trim operation
input := TrimRequest{
Operation: Operation{
Station: "Trimmer station",
User: "operator@dev.com",
},
OriginalSha1: ofi.Sha1,
ProxySha1: pfi.Sha1,
Original: AVFile{
File: File{
FileName: "original_trim.mp4",
Sha1: "012356789abcdef012356789abcdef1111111111",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 892.1900,
},
Proxy: &AVFile{
File: File{
FileName: "proxy_trim.mp4",
Sha1: "987653210abcdef012356789abcdef2222222222",
Size: 987,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 891.8800,
},
CaptureSource: "mltcap",
In: []float64{10.05, 249.43},
Out: []float64{240.51, 899.27},
}
op, evnts, err := handleTrim(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_TRIM].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.CaptureSource, props["capture_source"], "properties: capture_source")
for i, v := range input.In {
suite.Equal(v, props["in"].([]interface{})[i], "properties: in[%d]", i)
}
for i, v := range input.Out {
suite.Equal(v, props["out"].([]interface{})[i], "properties: out[%d]", i)
}
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 4, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
originalParent := fm[ofi.FileName]
proxyParent := fm[pfi.FileName]
// Check original
original := fm[input.Original.FileName]
suite.Equal(input.Original.FileName, original.Name, "Original: Name")
suite.Equal(input.Original.Sha1, hex.EncodeToString(original.Sha1.Bytes), "Original: SHA1")
suite.Equal(input.Original.Size, original.Size, "Original: Size")
suite.Equal(input.Original.CreatedAt.Time.Unix(), original.FileCreatedAt.Time.Unix(), "Original: FileCreatedAt")
suite.Equal(originalParent.ID, original.ParentID.Int64, "Original Parent.ID")
err = original.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Original.Duration, props["duration"], "Original props: duration")
// Check proxy
proxy := fm[input.Proxy.FileName]
suite.Equal(input.Proxy.FileName, proxy.Name, "Proxy: Name")
suite.Equal(input.Proxy.Sha1, hex.EncodeToString(proxy.Sha1.Bytes), "Proxy: SHA1")
suite.Equal(input.Proxy.Size, proxy.Size, "Proxy: Size")
suite.Equal(input.Proxy.CreatedAt.Time.Unix(), proxy.FileCreatedAt.Time.Unix(), "Proxy: FileCreatedAt")
suite.Equal(proxyParent.ID, proxy.ParentID.Int64, "Proxy Parent.ID")
err = proxy.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Proxy.Duration, props["duration"], "Proxy props: duration")
}
func (suite *HandlersSuite) TestHandleTrimNoProxy() {
// Create dummy original parent file
ofi := File{
FileName: "dummy original parent file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, ofi, nil)
suite.Require().Nil(err)
// Do trim operation
input := TrimRequest{
Operation: Operation{
Station: "Trimmer station",
User: "operator@dev.com",
},
OriginalSha1: ofi.Sha1,
Original: AVFile{
File: File{
FileName: "original_trim.mp4",
Sha1: "012356789abcdef012356789abcdef1111111111",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 892.1900,
},
CaptureSource: "capture_without_proxy",
In: []float64{10.05, 249.43},
Out: []float64{240.51, 899.27},
}
op, evnts, err := handleTrim(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_TRIM].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.CaptureSource, props["capture_source"], "properties: capture_source")
for i, v := range input.In {
suite.Equal(v, props["in"].([]interface{})[i], "properties: in[%d]", i)
}
for i, v := range input.Out {
suite.Equal(v, props["out"].([]interface{})[i], "properties: out[%d]", i)
}
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 2, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
originalParent := fm[ofi.FileName]
// Check original
original := fm[input.Original.FileName]
suite.Equal(input.Original.FileName, original.Name, "Original: Name")
suite.Equal(input.Original.Sha1, hex.EncodeToString(original.Sha1.Bytes), "Original: SHA1")
suite.Equal(input.Original.Size, original.Size, "Original: Size")
suite.Equal(input.Original.CreatedAt.Time.Unix(), original.FileCreatedAt.Time.Unix(), "Original: FileCreatedAt")
suite.Equal(originalParent.ID, original.ParentID.Int64, "Original Parent.ID")
err = original.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Original.Duration, props["duration"], "Original props: duration")
}
func (suite *HandlersSuite) TestHandleSend() {
// Create dummy original and proxy trimmed files
ofi := File{
FileName: "dummy original trimmed file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, ofi, nil)
suite.Require().Nil(err)
pfi := File{
FileName: "dummy proxy trimmed file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "987653210abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
_, err = CreateFile(suite.tx, nil, pfi, nil)
suite.Require().Nil(err)
// Do send operation
input := SendRequest{
Operation: Operation{
Station: "Trimmer station",
User: "operator@dev.com",
WorkflowID: "t123456789",
},
Original: Rename{
Sha1: ofi.Sha1,
FileName: "original_renamed.mp4",
},
Proxy: &Rename{
Sha1: pfi.Sha1,
FileName: "proxy_renamed.mp4",
},
Metadata: CITMetadata{
ContentType: common.CT_LESSON_PART,
},
}
op, evnts, err := handleSend(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_SEND].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"], "properties: workflow_id")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 2, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
// Check original
original := fm[input.Original.FileName]
suite.Equal(input.Original.FileName, original.Name, "Original: Name")
suite.Equal(input.Original.Sha1, hex.EncodeToString(original.Sha1.Bytes), "Original: SHA1")
// Check proxy
proxy := fm[input.Proxy.FileName]
suite.Equal(input.Proxy.FileName, proxy.Name, "Proxy: Name")
suite.Equal(input.Proxy.Sha1, hex.EncodeToString(proxy.Sha1.Bytes), "Proxy: SHA1")
}
func (suite *HandlersSuite) TestHandleSendNoProxy() {
// Create dummy original trimmed file
ofi := File{
FileName: "dummy original trimmed file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, ofi, nil)
suite.Require().Nil(err)
// Do send operation
input := SendRequest{
Operation: Operation{
Station: "Trimmer station",
User: "operator@dev.com",
WorkflowID: "t123456789",
},
Original: Rename{
Sha1: ofi.Sha1,
FileName: "original_renamed.mp4",
},
Metadata: CITMetadata{
ContentType: common.CT_LESSON_PART,
},
}
op, evnts, err := handleSend(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_SEND].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"], "properties: workflow_id")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
// Check original
original := fm[input.Original.FileName]
suite.Equal(input.Original.FileName, original.Name, "Original: Name")
suite.Equal(input.Original.Sha1, hex.EncodeToString(original.Sha1.Bytes), "Original: SHA1")
}
func (suite *HandlersSuite) TestHandleConvert() {
// Create dummy input file
fi := File{
FileName: "dummy input file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, fi, nil)
suite.Require().Nil(err)
// Do convert operation
input := ConvertRequest{
Operation: Operation{
Station: "Trimmer station",
User: "operator@dev.com",
},
Sha1: fi.Sha1,
Output: []HLSFile{
{
AVFile: AVFile{
File: File{
FileName: "heb_file.mp4",
Sha1: "0987654321fedcba0987654321fedcba33333333",
Size: 694,
CreatedAt: &Timestamp{Time: time.Now()},
Type: "type1",
SubType: "subtype1",
MimeType: "mime_type1",
Language: common.LANG_HEBREW,
},
Duration: 871,
},
},
{
AVFile: AVFile{
File: File{
FileName: "eng_file.mp4",
Sha1: "0987654321fedcba0987654321fedcba44444444",
Size: 694,
CreatedAt: &Timestamp{Time: time.Now()},
Type: "type2",
SubType: "subtype2",
MimeType: "mime_type2",
Language: common.LANG_ENGLISH,
},
Duration: 871,
},
},
{
AVFile: AVFile{
File: File{
FileName: "rus_file.mp4",
Sha1: "0987654321fedcba0987654321fedcba55555555",
Size: 694,
CreatedAt: &Timestamp{Time: time.Now()},
Type: "type3",
SubType: "subtype3",
MimeType: "mime_type3",
Language: common.LANG_RUSSIAN,
},
Duration: 871,
},
},
{
AVFile: AVFile{
File: File{
FileName: "duplicate_rus_file.mp4",
Sha1: "0987654321fedcba0987654321fedcba55555555",
Size: 694,
CreatedAt: &Timestamp{Time: time.Now()},
Type: "type3",
SubType: "subtype3",
MimeType: "mime_type3",
Language: common.LANG_RUSSIAN,
},
Duration: 871,
},
},
},
}
op, evnts, err := handleConvert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Empty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_CONVERT].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
suite.False(op.Properties.Valid, "Operation properties")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 4, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
// Check input
in := fm[fi.FileName]
suite.Equal(fi.Sha1, hex.EncodeToString(in.Sha1.Bytes), "In: SHA1")
// Check output
var props map[string]interface{}
for i, x := range input.Output[:len(input.Output)-2] {
f := fm[x.FileName]
suite.Equal(x.FileName, f.Name, "Output[%d]: Name", i)
suite.Equal(x.Sha1, hex.EncodeToString(f.Sha1.Bytes), "Output[%d]: SHA1", i)
suite.Equal(x.Size, f.Size, "Output[%d]: Size", i)
suite.Equal(x.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "Output[%d]: FileCreatedAt", i)
suite.Equal(x.Type, f.Type, "Output[%d]: Type", i)
suite.Equal(x.SubType, f.SubType, "Output[%d]: SubType", i)
suite.Equal(x.MimeType, f.MimeType.String, "Output[%d]: MimeType", i)
suite.Equal(x.Language, f.Language.String, "Output[%d]: Language", i)
suite.Equal(in.ID, f.ParentID.Int64, "Output[%d] Parent.ID", i)
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(x.Duration, props["duration"], "Output[%d] props: duration", i)
}
// test "reconvert" update existing files
efi := File{
FileName: "dummy input file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9999999999",
Size: math.MaxInt64,
}
_, err = CreateFile(suite.tx, nil, efi, nil)
suite.Require().Nil(err)
input.Output = []HLSFile{
{
AVFile: AVFile{
File: File{
FileName: "heb_file.mp4",
Sha1: "012356789abcdef012356789abcdef9999999999",
Size: math.MaxInt64,
CreatedAt: &Timestamp{Time: time.Now()},
Type: "type1",
SubType: "subtype1",
MimeType: "mime_type1",
Language: common.LANG_HEBREW,
},
Duration: 871,
},
},
}
op, evnts, err = handleConvert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 2, "Number of files")
fm = make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
// Check output
for i, x := range input.Output {
f := fm[x.FileName]
suite.Equal(x.FileName, f.Name, "Output[%d]: Name", i)
suite.Equal(x.Sha1, hex.EncodeToString(f.Sha1.Bytes), "Output[%d]: SHA1", i)
suite.Equal(x.Size, f.Size, "Output[%d]: Size", i)
suite.Equal(x.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "Output[%d]: FileCreatedAt", i)
suite.Equal(x.Type, f.Type, "Output[%d]: Type", i)
suite.Equal(x.SubType, f.SubType, "Output[%d]: SubType", i)
suite.Equal(x.MimeType, f.MimeType.String, "Output[%d]: MimeType", i)
suite.Equal(x.Language, f.Language.String, "Output[%d]: Language", i)
suite.Equal(in.ID, f.ParentID.Int64, "Output[%d] Parent.ID", i)
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(x.Duration, props["duration"], "Output[%d] props: duration", i)
}
}
func (suite *HandlersSuite) TestHandleUpload() {
// First seen, unknown, file
input := UploadRequest{
Operation: Operation{
Station: "Upload station",
User: "operator@dev.com",
},
AVFile: AVFile{
File: File{
FileName: "file.mp4",
Sha1: "0987654321fedcba0987654321fedcba33333333",
Size: 694,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 871,
},
Url: "http://example.com/some/url/to/file.mp4",
}
op, evnts, err := handleUpload(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_UPLOAD].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
suite.False(op.Properties.Valid, "Operation properties")
// Check file
err = op.L.LoadFiles(suite.tx, true, op, nil)
suite.Require().Nil(err)
suite.Require().Len(op.R.Files, 1, "Operation Files length")
f := op.R.Files[0]
suite.Equal(input.FileName, f.Name, "File.Name")
suite.Equal(input.Sha1, hex.EncodeToString(f.Sha1.Bytes), "File.SHA1")
suite.Equal(input.Size, f.Size, "File.Size")
suite.Equal(input.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "File.FileCreatedAt")
suite.False(f.ParentID.Valid, "File.ParentID")
suite.True(f.Published, "File.Published")
suite.Equal(common.SEC_PUBLIC, f.Secure, "File.Secure")
var props map[string]interface{}
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Url, props["url"], "file props: url")
suite.Equal(input.Duration, props["duration"], "file props: duration")
// Existing file in a content unit and collection structure
f2 := File{
FileName: "file.mp4",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef0123456789",
Size: math.MaxInt64,
}
file, err := CreateFile(suite.tx, nil, f2, nil)
suite.Require().Nil(err)
cu, err := CreateContentUnit(suite.tx, common.CT_LESSON_PART, nil)
suite.Require().Nil(err)
err = file.SetContentUnit(suite.tx, false, cu)
suite.Require().Nil(err)
c, err := CreateCollection(suite.tx, common.CT_DAILY_LESSON, nil)
suite.Require().Nil(err)
err = c.AddCollectionsContentUnits(suite.tx, true, &models.CollectionsContentUnit{ContentUnitID: cu.ID})
suite.Require().Nil(err)
input = UploadRequest{
Operation: Operation{
Station: "Upload station",
User: "operator@dev.com",
},
AVFile: AVFile{
File: f2,
Duration: 871,
},
Url: "http://example.com/some/url/to/file.mp4",
}
op, evnts, err = handleUpload(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_UPLOAD].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
suite.False(op.Properties.Valid, "Operation properties")
// Check file
err = op.L.LoadFiles(suite.tx, true, op, nil)
suite.Require().Nil(err)
suite.Require().Len(op.R.Files, 1, "Operation Files length")
f = op.R.Files[0]
suite.Equal(input.FileName, f.Name, "File.Name")
suite.Equal(input.Sha1, hex.EncodeToString(f.Sha1.Bytes), "File.SHA1")
suite.Equal(input.Size, f.Size, "File.Size")
suite.Equal(input.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "File.FileCreatedAt")
suite.False(f.ParentID.Valid, "File.ParentID")
suite.True(f.Published, "File.Published")
suite.Equal(common.SEC_PUBLIC, f.Secure, "File.Secure")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Url, props["url"], "file props: url")
suite.Equal(input.Duration, props["duration"], "file props: duration")
// Check content unit and collection
err = cu.Reload(suite.tx)
suite.Require().Nil(err)
suite.True(cu.Published)
err = c.Reload(suite.tx)
suite.Require().Nil(err)
suite.True(c.Published)
}
func (suite *HandlersSuite) TestHandleSirtutim() {
// Create dummy original parent files
ofi := File{
FileName: "dummy original parent file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
original, err := CreateFile(suite.tx, nil, ofi, nil)
suite.Require().Nil(err)
// Create dummy content unit
cu, err := CreateContentUnit(suite.tx, common.CT_LESSON_PART, nil)
suite.Require().Nil(err)
// associate original and content unit
original.ContentUnitID = null.Int64From(cu.ID)
_, err = original.Update(suite.tx, boil.Whitelist("content_unit_id"))
suite.Require().Nil(err)
// Do sirtutim operation
input := SirtutimRequest{
Operation: Operation{
Station: "Some station",
User: "operator@dev.com",
},
OriginalSha1: ofi.Sha1,
File: File{
FileName: "sirtutim.zip",
Sha1: "012356789abcdef012356789abcdef1111111111",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
},
}
op, evnts, err := handleSirtutim(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_SIRTUTIM].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
suite.False(op.Properties.Valid, "properties.Valid")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 2, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
originalParent := fm[ofi.FileName]
suite.Equal(original.ID, originalParent.ID, "original <-> operation")
// Check sirtutim file
sirtutim := fm[input.FileName]
suite.Equal(input.FileName, sirtutim.Name, "sirtutim: Name")
suite.Equal(input.Sha1, hex.EncodeToString(sirtutim.Sha1.Bytes), "sirtutim: SHA1")
suite.Equal(input.Size, sirtutim.Size, "sirtutim: Size")
suite.Equal(input.CreatedAt.Time.Unix(), sirtutim.FileCreatedAt.Time.Unix(), "sirtutim: FileCreatedAt")
// check content unit association
suite.True(sirtutim.ContentUnitID.Valid, "sirtutim: ContentUnitID.Valid")
suite.Equal(cu.ID, sirtutim.ContentUnitID.Int64, "sirtutim: ContentUnitID.Int64")
}
func (suite *HandlersSuite) TestHandleInsert() {
// Create dummy content unit
cu, err := CreateContentUnit(suite.tx, common.CT_LESSON_PART, nil)
suite.Require().Nil(err)
// Do insert operation
input := InsertRequest{
Operation: Operation{
Station: "Some station",
User: "operator@dev.com",
WorkflowID: "workflow_id",
},
InsertType: "akladot",
ContentUnitUID: cu.UID,
AVFile: AVFile{
File: File{
FileName: "akladot.doc",
Sha1: "012356789abcdef012356789abcdef1111111111",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
MimeType: "application/msword",
Language: common.LANG_HEBREW,
},
Duration: 123.4,
},
Mode: "new",
}
op, evnts, err := handleInsert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_INSERT].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"].(string), "Operation workflow_id")
suite.Equal(input.InsertType, props["insert_type"].(string), "Operation insert_type")
suite.Equal(input.Mode, props["mode"].(string), "Operation mode")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
// check inserted file
f := op.R.Files[0]
suite.Equal(input.FileName, f.Name, "File Name")
suite.Equal(input.Sha1, hex.EncodeToString(f.Sha1.Bytes), "File SHA1")
suite.Equal(input.Size, f.Size, "File Size")
suite.Equal(input.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "File FileCreatedAt")
suite.Equal("text", f.Type, "File Type")
suite.Equal(input.MimeType, f.MimeType.String, "File MimeType")
suite.Equal(input.Language, f.Language.String, "File Language")
suite.False(f.ParentID.Valid, "File ParentID")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.InsertType, props["insert_type"].(string), "File insert_type")
suite.Equal(input.AVFile.Duration, props["duration"], "File duration")
// check content unit association
suite.True(f.ContentUnitID.Valid, "File ContentUnitID.Valid")
suite.Equal(cu.ID, f.ContentUnitID.Int64, "File ContentUnitID.Int64")
err = cu.Reload(suite.tx)
suite.Require().Nil(err)
err = cu.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(int(input.AVFile.Duration), int(props["duration"].(float64)), "CU duration")
// test with parent file
pfi := File{
FileName: "dummy parent file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
parent, err := CreateFile(suite.tx, nil, pfi, nil)
suite.Require().Nil(err)
input.ParentSha1 = pfi.Sha1
input.Sha1 = "012356789abcdef012356789abcdef1111111112"
op, evnts, err = handleInsert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// check file's ParentID has changed
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 2, "Number of files")
f = op.R.Files[0]
if op.R.Files[1].Language.String != "" {
f = op.R.Files[1]
}
suite.True(f.ParentID.Valid, "File ParentID.Valid")
suite.Equal(parent.ID, f.ParentID.Int64, "File ParentID.Int64")
// test when file already exists
cu2, err := CreateContentUnit(suite.tx, common.CT_LESSON_PART, nil)
suite.Require().Nil(err)
input.ContentUnitUID = cu2.UID
op, evnts, err = handleInsert(suite.tx, input)
suite.Require().NotNil(err)
}
func (suite *HandlersSuite) TestHandleInsertKiteiMakor() {
// Create dummy content unit
cu, err := CreateContentUnit(suite.tx, common.CT_LESSON_PART, nil)
suite.Require().Nil(err)
for i, iType := range []string{"kitei-makor", "research-material"} {
var cType string
switch iType {
case "kitei-makor":
cType = common.CT_KITEI_MAKOR
case "research-material":
cType = common.CT_RESEARCH_MATERIAL
}
// Do insert operation
input := InsertRequest{
Operation: Operation{
Station: "Some station",
User: "operator@dev.com",
WorkflowID: "workflow_id",
},
InsertType: iType,
ContentUnitUID: cu.UID,
AVFile: AVFile{
File: File{
FileName: fmt.Sprintf("%s.docx", iType),
Sha1: fmt.Sprintf("012356789abcdef012356789abcdef111111111%d", i),
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
MimeType: common.MEDIA_TYPE_REGISTRY.ByExtension["docx"].MimeType,
Language: common.LANG_HEBREW,
},
},
Mode: "new",
}
op, evnts, err := handleInsert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_INSERT].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"].(string), "Operation workflow_id")
suite.Equal(input.InsertType, props["insert_type"].(string), "Operation insert_type")
suite.Equal(input.Mode, props["mode"].(string), "Operation mode")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
// check inserted file
f := op.R.Files[0]
suite.Equal(input.FileName, f.Name, "File Name")
suite.Equal(input.Sha1, hex.EncodeToString(f.Sha1.Bytes), "File SHA1")
suite.Equal(input.Size, f.Size, "File Size")
suite.Equal(input.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "File FileCreatedAt")
suite.Equal("text", f.Type, "File Type")
suite.Equal(input.MimeType, f.MimeType.String, "File MimeType")
suite.Equal(input.Language, f.Language.String, "File Language")
suite.False(f.ParentID.Valid, "File ParentID")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.InsertType, props["insert_type"].(string), "File insert_type")
suite.Nil(props["duration"], "File duration")
// check content unit association
suite.Require().Nil(f.L.LoadContentUnit(suite.tx, true, f, nil))
ktCU := f.R.ContentUnit
suite.Equal(cType, common.CONTENT_TYPE_REGISTRY.ByID[ktCU.TypeID].Name, "KT CU type")
suite.Require().Nil(ktCU.L.LoadDerivedContentUnitDerivations(suite.tx, true, ktCU, nil))
suite.Equal(cu.ID, ktCU.R.DerivedContentUnitDerivations[0].SourceID, "KT CU source CU")
// test when KT cu exists
input.FileName = fmt.Sprintf("%s2.docx", iType)
input.Sha1 = fmt.Sprintf("012356789abcdef012356789abcdef111111112%d", i)
op2, evnts, err := handleInsert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_INSERT].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"].(string), "Operation workflow_id")
suite.Equal(input.InsertType, props["insert_type"].(string), "Operation insert_type")
suite.Equal(input.Mode, props["mode"].(string), "Operation mode")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
// check inserted file
f2 := op2.R.Files[0]
suite.Equal(input.FileName, f2.Name, "File Name")
suite.Equal(input.Sha1, hex.EncodeToString(f2.Sha1.Bytes), "File SHA1")
suite.Equal(input.Size, f2.Size, "File Size")
suite.Equal(input.CreatedAt.Time.Unix(), f2.FileCreatedAt.Time.Unix(), "File FileCreatedAt")
suite.Equal("text", f2.Type, "File Type")
suite.Equal(input.MimeType, f2.MimeType.String, "File MimeType")
suite.Equal(input.Language, f2.Language.String, "File Language")
suite.False(f2.ParentID.Valid, "File ParentID")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.InsertType, props["insert_type"].(string), "File insert_type")
suite.Nil(props["duration"], "File duration")
// check content unit association
suite.True(f2.ContentUnitID.Valid, "f2.ContentUnitID.Valid")
suite.Equal(f.ContentUnitID.Int64, f2.ContentUnitID.Int64, "f2.ContentUnitID.Int64")
}
}
func (suite *HandlersSuite) TestHandleInsertPublication() {
// Create dummy content unit
cu, err := CreateContentUnit(suite.tx, common.CT_ARTICLE, nil)
suite.Require().Nil(err)
// create dummy publisher
publisher := models.Publisher{
UID: "12345678",
}
suite.Require().Nil(publisher.Insert(suite.tx, boil.Infer()))
// Do insert operation
input := InsertRequest{
Operation: Operation{
Station: "Some station",
User: "operator@dev.com",
WorkflowID: "workflow_id",
},
InsertType: "publication",
PublisherUID: publisher.UID,
ContentUnitUID: cu.UID,
AVFile: AVFile{
File: File{
FileName: "publication.png",
Sha1: "012356789abcdef012356789abcdef1111111111",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
MimeType: common.MEDIA_TYPE_REGISTRY.ByExtension["png"].MimeType,
Language: common.LANG_HEBREW,
},
},
Mode: "new",
}
op, evnts, err := handleInsert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_INSERT].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"].(string), "Operation workflow_id")
suite.Equal(input.InsertType, props["insert_type"].(string), "Operation insert_type")
suite.Equal(input.Mode, props["mode"].(string), "Operation mode")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
// check inserted file
f := op.R.Files[0]
suite.Equal(input.FileName, f.Name, "File Name")
suite.Equal(input.Sha1, hex.EncodeToString(f.Sha1.Bytes), "File SHA1")
suite.Equal(input.Size, f.Size, "File Size")
suite.Equal(input.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "File FileCreatedAt")
suite.Equal("image", f.Type, "File Type")
suite.Equal(input.MimeType, f.MimeType.String, "File MimeType")
suite.Equal(input.Language, f.Language.String, "File Language")
suite.False(f.ParentID.Valid, "File ParentID")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.InsertType, props["insert_type"].(string), "File insert_type")
suite.Nil(props["duration"], "File duration")
// check content unit association
suite.Require().Nil(f.L.LoadContentUnit(suite.tx, true, f, nil))
pCU := f.R.ContentUnit
suite.Equal(common.CT_PUBLICATION, common.CONTENT_TYPE_REGISTRY.ByID[pCU.TypeID].Name, "Publication CU type")
suite.Require().Nil(pCU.L.LoadDerivedContentUnitDerivations(suite.tx, true, pCU, nil))
suite.Equal(cu.ID, pCU.R.DerivedContentUnitDerivations[0].SourceID, "Publication CU source CU")
// test when Publication cu exists
input.FileName = "publication2.png"
input.Sha1 = "012356789abcdef012356789abcdef1111111112"
op2, evnts, err := handleInsert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_INSERT].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"].(string), "Operation workflow_id")
suite.Equal(input.InsertType, props["insert_type"].(string), "Operation insert_type")
suite.Equal(input.Mode, props["mode"].(string), "Operation mode")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
// check inserted file
f2 := op2.R.Files[0]
suite.Equal(input.FileName, f2.Name, "File Name")
suite.Equal(input.Sha1, hex.EncodeToString(f2.Sha1.Bytes), "File SHA1")
suite.Equal(input.Size, f2.Size, "File Size")
suite.Equal(input.CreatedAt.Time.Unix(), f2.FileCreatedAt.Time.Unix(), "File FileCreatedAt")
suite.Equal("image", f2.Type, "File Type")
suite.Equal(input.MimeType, f2.MimeType.String, "File MimeType")
suite.Equal(input.Language, f2.Language.String, "File Language")
suite.False(f2.ParentID.Valid, "File ParentID")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.InsertType, props["insert_type"].(string), "File insert_type")
suite.Nil(props["duration"], "File duration")
// check content unit association
suite.True(f2.ContentUnitID.Valid, "f2.ContentUnitID.Valid")
suite.Equal(f.ContentUnitID.Int64, f2.ContentUnitID.Int64, "f2.ContentUnitID.Int64")
}
func (suite *HandlersSuite) TestHandleInsertDeclamation() {
// Do insert operation
input := InsertRequest{
Operation: Operation{
Station: "Some station",
User: "operator@dev.com",
WorkflowID: "workflow_id",
},
InsertType: "declamation",
AVFile: AVFile{
File: File{
FileName: "declamation.mp3",
Sha1: "012356789abcdef012356789abcdef1111111112",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
MimeType: common.MEDIA_TYPE_REGISTRY.ByExtension["mp3"].MimeType,
Language: common.LANG_RUSSIAN,
},
Duration: 987.6,
},
Mode: "new",
Metadata: &CITMetadata{
ContentType: common.CT_BLOG_POST,
FinalName: "final_name",
CaptureDate: Date{time.Now()},
Language: common.LANG_RUSSIAN,
Lecturer: "norav",
},
}
op, evnts, err := handleInsert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_INSERT].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"].(string), "Operation workflow_id")
suite.Equal(input.InsertType, props["insert_type"].(string), "Operation insert_type")
suite.Equal(input.Mode, props["mode"].(string), "Operation mode")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
// check inserted file
f := op.R.Files[0]
suite.Equal(input.FileName, f.Name, "File Name")
suite.Equal(input.Sha1, hex.EncodeToString(f.Sha1.Bytes), "File SHA1")
suite.Equal(input.Size, f.Size, "File Size")
suite.Equal(input.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "File FileCreatedAt")
suite.Equal("audio", f.Type, "File Type")
suite.Equal(input.MimeType, f.MimeType.String, "File MimeType")
suite.Equal(input.Language, f.Language.String, "File Language")
suite.False(f.ParentID.Valid, "File ParentID")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.InsertType, props["insert_type"].(string), "File insert_type")
suite.Equal(input.AVFile.Duration, props["duration"], "File duration")
// check content unit association
suite.Require().Nil(f.L.LoadContentUnit(suite.tx, true, f, nil))
cu := f.R.ContentUnit
suite.Equal(common.CT_BLOG_POST, common.CONTENT_TYPE_REGISTRY.ByID[cu.TypeID].Name, "CU type")
suite.Require().True(cu.Properties.Valid)
err = cu.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Metadata.CaptureDate.Format("2006-01-02"), props["film_date"], "cu.Properties[\"capture_date\"]")
suite.Equal(common.StdLang(input.Metadata.Language), props["original_language"], "cu.Properties[\"original_language\"]")
suite.Equal(int(input.AVFile.Duration), int(props["duration"].(float64)), "cu.Properties[\"duration\"]")
}
func (suite *HandlersSuite) TestHandleInsertUpdateMode() {
// Create dummy content unit
cu, err := CreateContentUnit(suite.tx, common.CT_LESSON_PART, nil)
suite.Require().Nil(err)
// Create dummy old file
ofi := File{
FileName: "dummy old file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
oldFile, err := CreateFile(suite.tx, nil, ofi, nil)
suite.Require().Nil(err)
err = cu.AddFiles(suite.tx, false, oldFile)
suite.Require().Nil(err)
// Do insert operation
input := InsertRequest{
Operation: Operation{
Station: "Some station",
User: "operator@dev.com",
WorkflowID: "workflow_id",
},
InsertType: "akladot",
ContentUnitUID: cu.UID,
AVFile: AVFile{
File: File{
FileName: "akladot.doc",
Sha1: "012356789abcdef012356789abcdef1111111111",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
MimeType: "application/msword",
Language: common.LANG_HEBREW,
},
Duration: 123.4,
},
Mode: "update",
OldSha1: ofi.Sha1,
}
op, evnts, err := handleInsert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_INSERT].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"].(string), "Operation workflow_id")
suite.Equal(input.InsertType, props["insert_type"].(string), "Operation insert_type")
suite.Equal(input.Mode, props["mode"].(string), "Operation mode")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 2, "Number of files")
f, of := op.R.Files[0], op.R.Files[1]
if f.Name != "akladot.doc" {
f, of = of, f
}
// check inserted file
suite.Equal(input.FileName, f.Name, "File Name")
suite.Equal(input.Sha1, hex.EncodeToString(f.Sha1.Bytes), "File SHA1")
suite.Equal(input.Size, f.Size, "File Size")
suite.Equal(input.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "File FileCreatedAt")
suite.Equal("text", f.Type, "File Type")
suite.Equal(input.MimeType, f.MimeType.String, "File MimeType")
suite.Equal(input.Language, f.Language.String, "File Language")
suite.False(f.ParentID.Valid, "File ParentID")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.InsertType, props["insert_type"].(string), "File insert_type")
suite.Equal(input.AVFile.Duration, props["duration"], "File duration")
// check content unit association
suite.True(f.ContentUnitID.Valid, "File ContentUnitID.Valid")
suite.Equal(cu.ID, f.ContentUnitID.Int64, "File ContentUnitID.Int64")
// check old file removed
suite.True(of.RemovedAt.Valid, "Old File RemovedAt.Valid")
}
func (suite *HandlersSuite) TestHandleInsertRenameMode() {
// Create dummy content unit
cu, err := CreateContentUnit(suite.tx, common.CT_LESSON_PART, nil)
suite.Require().Nil(err)
cu2, err := CreateContentUnit(suite.tx, common.CT_LESSON_PART, nil)
suite.Require().Nil(err)
// Create dummy old file
ofi := File{
FileName: "dummy file",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
Type: "video",
SubType: "video subtype",
MimeType: "video/mp4",
Language: common.LANG_RUSSIAN,
}
oldFile, err := CreateFile(suite.tx, nil, ofi, nil)
suite.Require().Nil(err)
err = cu.AddFiles(suite.tx, false, oldFile)
suite.Require().Nil(err)
// Do insert operation
input := InsertRequest{
Operation: Operation{
Station: "Some station",
User: "operator@dev.com",
WorkflowID: "workflow_id",
},
InsertType: "akladot",
ContentUnitUID: cu2.UID,
AVFile: AVFile{
File: File{
FileName: "akladot.doc",
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
MimeType: "application/msword",
Language: common.LANG_HEBREW,
},
Duration: 123.4,
},
Mode: "rename",
}
op, evnts, err := handleInsert(suite.tx, input)
suite.Require().Nil(err)
suite.Require().NotEmpty(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_INSERT].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Operation.WorkflowID, props["workflow_id"].(string), "Operation workflow_id")
suite.Equal(input.InsertType, props["insert_type"].(string), "Operation insert_type")
suite.Equal(input.Mode, props["mode"].(string), "Operation mode")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
f := op.R.Files[0]
// check inserted file
suite.Equal(input.FileName, f.Name, "File Name")
suite.Equal(ofi.Sha1, hex.EncodeToString(f.Sha1.Bytes), "File SHA1")
suite.Equal(ofi.Size, f.Size, "File Size")
suite.Equal(input.CreatedAt.Time.Unix(), f.FileCreatedAt.Time.Unix(), "File FileCreatedAt")
suite.Equal("text", f.Type, "File Type")
suite.Equal(input.MimeType, f.MimeType.String, "File MimeType")
suite.Equal(input.Language, f.Language.String, "File Language")
suite.False(f.ParentID.Valid, "File ParentID")
err = f.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.InsertType, props["insert_type"].(string), "File insert_type")
// check content unit association
suite.True(f.ContentUnitID.Valid, "File ContentUnitID.Valid")
suite.Equal(cu2.ID, f.ContentUnitID.Int64, "File ContentUnitID.Int64")
}
func (suite *HandlersSuite) TestHandleTranscodeSuccess() {
// Create dummy original file
ofi := File{
FileName: "dummy_original_file.wmv",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
Type: "video",
MimeType: common.MEDIA_TYPE_REGISTRY.ByExtension["wmv"].MimeType,
Language: common.LANG_HEBREW,
}
oProps := map[string]interface{}{
"duration": 1234,
}
original, err := CreateFile(suite.tx, nil, ofi, oProps)
suite.Require().Nil(err)
// Create dummy content unit
cu, err := CreateContentUnit(suite.tx, common.CT_LESSON_PART, nil)
suite.Require().Nil(err)
// associate original and content unit
original.ContentUnitID = null.Int64From(cu.ID)
_, err = original.Update(suite.tx, boil.Whitelist("content_unit_id"))
suite.Require().Nil(err)
// Do transcode operation
input := TranscodeRequest{
Operation: Operation{
Station: "Some station",
User: "operator@dev.com",
},
OriginalSha1: ofi.Sha1,
MaybeFile: MaybeFile{
FileName: "dummy_original_file.mp4",
Sha1: "012356789abcdef012356789abcdef1111111111",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
},
}
op, evnts, err := handleTranscode(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_TRANSCODE].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
suite.False(op.Properties.Valid, "properties.Valid")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 2, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
originalParent := fm[ofi.FileName]
suite.Equal(original.ID, originalParent.ID, "original <-> operation")
// Check transcoded file
mp4 := fm[input.FileName]
suite.Equal(input.FileName, mp4.Name, "mp4: Name")
suite.Equal(input.Sha1, hex.EncodeToString(mp4.Sha1.Bytes), "mp4: SHA1")
suite.Equal(input.Size, mp4.Size, "mp4: Size")
suite.Equal(input.CreatedAt.Time.Unix(), mp4.FileCreatedAt.Time.Unix(), "mp4: FileCreatedAt")
suite.Equal(common.MEDIA_TYPE_REGISTRY.ByExtension["mp4"].Type, mp4.Type, "mp4: Type")
suite.True(mp4.MimeType.Valid, "mp4: MimeType.Valid")
suite.Equal(common.MEDIA_TYPE_REGISTRY.ByExtension["mp4"].MimeType, mp4.MimeType.String, "mp4: Type")
suite.True(mp4.ParentID.Valid, "mp4: ParentID.Valid")
suite.Equal(original.ID, mp4.ParentID.Int64, "mp4: ParentID")
suite.True(mp4.Properties.Valid, "mp4: Properties.Valid")
var props map[string]interface{}
err = json.Unmarshal(mp4.Properties.JSON, &props)
suite.Require().Nil(err, "json.Unmarshal mp4.Properties")
suite.EqualValues(oProps["duration"], props["duration"], "mp4.Properties duration")
// check content unit association
suite.True(mp4.ContentUnitID.Valid, "mp4: ContentUnitID.Valid")
suite.Equal(cu.ID, mp4.ContentUnitID.Int64, "mp4: ContentUnitID.Int64")
// re-transcode
input.MaybeFile = MaybeFile{
FileName: "re-transcoded.mp4",
Sha1: "012356789abcdef012356789abcdef2222222222",
Size: 98738,
CreatedAt: &Timestamp{Time: time.Now()},
}
op, evnts, err = handleTranscode(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 3, "Number of files")
fm = make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
originalParent = fm[ofi.FileName]
suite.Equal(original.ID, originalParent.ID, "original <-> operation")
suite.Equal(mp4.ID, fm[mp4.Name].ID, "old transcoded <-> operation")
// Check re-transcoded file
mp4New := fm[input.FileName]
suite.Equal(input.FileName, mp4New.Name, "mp4New: Name")
suite.Equal(input.Sha1, hex.EncodeToString(mp4New.Sha1.Bytes), "mp4New: SHA1")
suite.Equal(input.Size, mp4New.Size, "mp4: Size")
suite.Equal(input.CreatedAt.Time.Unix(), mp4New.FileCreatedAt.Time.Unix(), "mp4New: FileCreatedAt")
suite.Equal(common.MEDIA_TYPE_REGISTRY.ByExtension["mp4"].Type, mp4New.Type, "mp4: Type")
suite.True(mp4New.MimeType.Valid, "mp4New: MimeType.Valid")
suite.Equal(common.MEDIA_TYPE_REGISTRY.ByExtension["mp4"].MimeType, mp4New.MimeType.String, "mp4New: Type")
suite.True(mp4New.ParentID.Valid, "mp4New: ParentID.Valid")
suite.Equal(original.ID, mp4New.ParentID.Int64, "mp4New: ParentID")
suite.True(mp4New.Properties.Valid, "mp4New: Properties.Valid")
err = json.Unmarshal(mp4New.Properties.JSON, &props)
suite.Require().Nil(err, "json.Unmarshal mp4New.Properties")
suite.EqualValues(oProps["duration"], props["duration"], "mp4New.Properties duration")
// Check old transcoded file
err = mp4.Reload(suite.tx)
suite.Require().Nil(err)
suite.True(mp4.RemovedAt.Valid, "old mp4 removed")
}
func (suite *HandlersSuite) TestHandleTranscodeError() {
// Create dummy original file
ofi := File{
FileName: "dummy_original_file.wmv",
CreatedAt: &Timestamp{time.Now()},
Sha1: "012356789abcdef012356789abcdef9876543210",
Size: math.MaxInt64,
}
original, err := CreateFile(suite.tx, nil, ofi, nil)
suite.Require().Nil(err)
// Do transcode operation
input := TranscodeRequest{
Operation: Operation{
Station: "Some station",
User: "operator@dev.com",
},
OriginalSha1: ofi.Sha1,
Message: "Some error description goes here",
}
op, evnts, err := handleTranscode(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_TRANSCODE].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
suite.True(op.Properties.Valid, "properties.Valid")
var props map[string]interface{}
err = json.Unmarshal(op.Properties.JSON, &props)
suite.Require().Nil(err, "json.Unmarshal properties")
suite.Equal(input.Message, props["message"], "op properties message")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 1, "Number of files")
originalParent := op.R.Files[0]
suite.Equal(original.ID, originalParent.ID, "original <-> operation")
}
func (suite *HandlersSuite) TestHandleJoin() {
// create dummy input files
inOriginals := make([]string, 3)
for i := 0; i < len(inOriginals); i++ {
fi := File{
FileName: fmt.Sprintf("dummy original file %d", i+1),
CreatedAt: &Timestamp{time.Now()},
Sha1: utils.RandomSHA1(),
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, fi, nil)
suite.Require().Nil(err)
inOriginals[i] = fi.Sha1
}
inProxies := make([]string, 3)
for i := 0; i < len(inProxies); i++ {
fi := File{
FileName: fmt.Sprintf("dummy proxy file %d", i+1),
CreatedAt: &Timestamp{time.Now()},
Sha1: utils.RandomSHA1(),
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, fi, nil)
suite.Require().Nil(err)
inProxies[i] = fi.Sha1
}
// Do join operation
input := JoinRequest{
Operation: Operation{
Station: "Joiner station",
User: "operator@dev.com",
},
OriginalShas: inOriginals,
ProxyShas: inProxies,
Original: AVFile{
File: File{
FileName: "original_join.mp4",
Sha1: "012356789abcdef012356789abcdef1111111111",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 892.1900,
},
Proxy: &AVFile{
File: File{
FileName: "proxy_join.mp4",
Sha1: "987653210abcdef012356789abcdef2222222222",
Size: 987,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 891.8800,
},
}
op, evnts, err := handleJoin(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_JOIN].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
for i, v := range input.OriginalShas {
suite.Equal(v, props["original_shas"].([]interface{})[i], "properties: original_shas[%d]", i)
}
for i, v := range input.ProxyShas {
suite.Equal(v, props["proxy_shas"].([]interface{})[i], "properties: proxy_shas[%d]", i)
}
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 8, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
// Check original
original := fm[input.Original.FileName]
suite.Equal(input.Original.FileName, original.Name, "Original: Name")
suite.Equal(input.Original.Sha1, hex.EncodeToString(original.Sha1.Bytes), "Original: SHA1")
suite.Equal(input.Original.Size, original.Size, "Original: Size")
suite.Equal(input.Original.CreatedAt.Time.Unix(), original.FileCreatedAt.Time.Unix(), "Original: FileCreatedAt")
err = original.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Original.Duration, props["duration"], "Original props: duration")
// Check proxy
proxy := fm[input.Proxy.FileName]
suite.Equal(input.Proxy.FileName, proxy.Name, "Proxy: Name")
suite.Equal(input.Proxy.Sha1, hex.EncodeToString(proxy.Sha1.Bytes), "Proxy: SHA1")
suite.Equal(input.Proxy.Size, proxy.Size, "Proxy: Size")
suite.Equal(input.Proxy.CreatedAt.Time.Unix(), proxy.FileCreatedAt.Time.Unix(), "Proxy: FileCreatedAt")
err = proxy.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Proxy.Duration, props["duration"], "Proxy props: duration")
}
func (suite *HandlersSuite) TestHandleJoinNoProxy() {
// create dummy input files
inOriginals := make([]string, 3)
for i := 0; i < len(inOriginals); i++ {
fi := File{
FileName: fmt.Sprintf("dummy original file %d", i+1),
CreatedAt: &Timestamp{time.Now()},
Sha1: utils.RandomSHA1(),
Size: math.MaxInt64,
}
_, err := CreateFile(suite.tx, nil, fi, nil)
suite.Require().Nil(err)
inOriginals[i] = fi.Sha1
}
// Do join operation
input := JoinRequest{
Operation: Operation{
Station: "Joiner station",
User: "operator@dev.com",
},
OriginalShas: inOriginals,
Original: AVFile{
File: File{
FileName: "original_join.mp4",
Sha1: "012356789abcdef012356789abcdef1111111111",
Size: 98737,
CreatedAt: &Timestamp{Time: time.Now()},
},
Duration: 892.1900,
},
}
op, evnts, err := handleJoin(suite.tx, input)
suite.Require().Nil(err)
suite.Require().Nil(evnts)
// Check op
suite.Equal(common.OPERATION_TYPE_REGISTRY.ByName[common.OP_JOIN].ID, op.TypeID, "Operation TypeID")
suite.Equal(input.Operation.Station, op.Station.String, "Operation Station")
var props map[string]interface{}
err = op.Properties.Unmarshal(&props)
suite.Require().Nil(err)
for i, v := range input.OriginalShas {
suite.Equal(v, props["original_shas"].([]interface{})[i], "properties: original_shas[%d]", i)
}
suite.Empty(props["proxy_shas"], "properties: proxy_shas should be empty")
// Check user
suite.Require().Nil(op.L.LoadUser(suite.tx, true, op, nil))
suite.Equal(input.Operation.User, op.R.User.Email, "Operation User")
// Check associated files
suite.Require().Nil(op.L.LoadFiles(suite.tx, true, op, nil))
suite.Len(op.R.Files, 4, "Number of files")
fm := make(map[string]*models.File)
for _, x := range op.R.Files {
fm[x.Name] = x
}
// Check original
original := fm[input.Original.FileName]
suite.Equal(input.Original.FileName, original.Name, "Original: Name")
suite.Equal(input.Original.Sha1, hex.EncodeToString(original.Sha1.Bytes), "Original: SHA1")
suite.Equal(input.Original.Size, original.Size, "Original: Size")
suite.Equal(input.Original.CreatedAt.Time.Unix(), original.FileCreatedAt.Time.Unix(), "Original: FileCreatedAt")
err = original.Properties.Unmarshal(&props)
suite.Require().Nil(err)
suite.Equal(input.Original.Duration, props["duration"], "Original props: duration")
}