diff --git a/broker/src/asapo_broker/database/database.go b/broker/src/asapo_broker/database/database.go index 3a0683bf301fd3bf4b41c4d54544a1a970c3b158..9f3dd53983a2efd148777a5060f7451a5f0dfbe7 100644 --- a/broker/src/asapo_broker/database/database.go +++ b/broker/src/asapo_broker/database/database.go @@ -1,8 +1,7 @@ package database type Agent interface { - GetNextRecord(db_name string) ([]byte, error) - GetRecordByID(dbname string, id int) ([]byte, error) + GetRecordFromDb(db_name string, op string, id int) ([]byte, error) Connect(string) error Close() Copy() Agent diff --git a/broker/src/asapo_broker/database/database_test.go b/broker/src/asapo_broker/database/database_test.go index 68b1eadb44e0e5a02a19c66994a0c4cfe9540fbb..d61896433bd16fa0143f166793214767107343a7 100644 --- a/broker/src/asapo_broker/database/database_test.go +++ b/broker/src/asapo_broker/database/database_test.go @@ -11,10 +11,9 @@ func TestMockDataBase(t *testing.T) { db.On("Connect", mock.AnythingOfType("string")).Return(nil) db.On("Close").Return() db.On("Copy").Return(nil) - db.On("GetNextRecord", "").Return([]byte(""), nil) - db.On("GetRecordByID", "").Return([]byte(""), nil) + db.On("GetRecordFromDb", "", "", 0).Return([]byte(""), nil) + db.Connect("") - db.GetNextRecord("") db.Close() db.Copy() var err DBError diff --git a/broker/src/asapo_broker/database/mock_database.go b/broker/src/asapo_broker/database/mock_database.go index 7ac5c13188e4c498566665b57b4448963d3fbe05..81ec5978cc7fc2fb095508f340834d170e888689 100644 --- a/broker/src/asapo_broker/database/mock_database.go +++ b/broker/src/asapo_broker/database/mock_database.go @@ -24,12 +24,7 @@ func (db *MockedDatabase) Copy() Agent { return db } -func (db *MockedDatabase) GetNextRecord(db_name string) (answer []byte, err error) { - args := db.Called(db_name) - return args.Get(0).([]byte), args.Error(1) -} - -func (db *MockedDatabase) GetRecordByID(db_name string, id int) (answer []byte, err error) { - args := db.Called(db_name, id) +func (db *MockedDatabase) GetRecordFromDb(db_name string, op string, id int) (answer []byte, err error) { + args := db.Called(db_name, op, id) return args.Get(0).([]byte), args.Error(1) } diff --git a/broker/src/asapo_broker/database/mongodb.go b/broker/src/asapo_broker/database/mongodb.go index b020d2a3a307f72778098a72beed10c1a3c8a273..9e290cf9f2f83292a8dbda095444bb2e40cb7613 100644 --- a/broker/src/asapo_broker/database/mongodb.go +++ b/broker/src/asapo_broker/database/mongodb.go @@ -139,6 +139,12 @@ func (db *Mongodb) createLocationPointers(dbname string) (err error) { return err } +func (db *Mongodb) setCounter(dbname string, ind int) (err error) { + update := bson.M{"$set": bson.M{pointer_field_name: ind}} + c := db.session.DB(dbname).C(pointer_collection_name) + return c.UpdateId(0, update) +} + func (db *Mongodb) incrementField(dbname string, max_ind int, res interface{}) (err error) { update := bson.M{"$inc": bson.M{pointer_field_name: 1}} change := mgo.Change{ @@ -155,7 +161,7 @@ func (db *Mongodb) incrementField(dbname string, max_ind int, res interface{}) ( return err } -func (db *Mongodb) GetRecordByID(dbname string, id int) ([]byte, error) { +func (db *Mongodb) GetRecordByID(dbname string, id int, returnID bool) ([]byte, error) { var res map[string]interface{} q := bson.M{"_id": id} c := db.session.DB(dbname).C(data_collection_name) @@ -167,7 +173,12 @@ func (db *Mongodb) GetRecordByID(dbname string, id int) ([]byte, error) { res, _ := json.Marshal(&r) log_str := "error getting record id " + strconv.Itoa(id) + " for " + dbname + " : " + err.Error() logger.Debug(log_str) - return nil, &DBError{utils.StatusNoData, string(res)} + if returnID { + return nil, &DBError{utils.StatusNoData, string(res)} + } else { + return nil, &DBError{utils.StatusNoData, err.Error()} + } + } log_str := "got record id " + strconv.Itoa(id) + " for " + dbname @@ -248,6 +259,37 @@ func (db *Mongodb) GetNextRecord(db_name string) ([]byte, error) { } log_str := "got next pointer " + strconv.Itoa(curPointer.Value) + " for " + db_name logger.Debug(log_str) - return db.GetRecordByID(db_name, curPointer.Value) + return db.GetRecordByID(db_name, curPointer.Value, true) + +} + +func (db *Mongodb) GetLastRecord(db_name string) ([]byte, error) { + + if err := db.checkDatabaseOperationPrerequisites(db_name); err != nil { + return nil, err + } + max_ind, err := db.getMaxIndex(db_name) + if err != nil { + log_str := "error getting last pointer for " + db_name + ":" + err.Error() + logger.Debug(log_str) + return nil, err + } + res, err := db.GetRecordByID(db_name, max_ind, false) + + db.setCounter(db_name, max_ind) + + return res, err +} + +func (db *Mongodb) GetRecordFromDb(db_name string, op string, id int) (answer []byte, err error) { + switch op { + case "next": + return db.GetNextRecord(db_name) + case "id": + return db.GetRecordByID(db_name, id, true) + case "last": + return db.GetLastRecord(db_name) + } + return nil, errors.New("Wrong db operation: " + op) } diff --git a/broker/src/asapo_broker/database/mongodb_test.go b/broker/src/asapo_broker/database/mongodb_test.go index 178346cfc1dfe82ed2a9b0a6b3920b034611f0a3..b5b5c18429815bc56c450990ef2db0cd798f4296 100644 --- a/broker/src/asapo_broker/database/mongodb_test.go +++ b/broker/src/asapo_broker/database/mongodb_test.go @@ -22,8 +22,10 @@ const dbaddress = "127.0.0.1:27017" var rec1 = TestRecord{1, "aaa"} var rec2 = TestRecord{2, "bbb"} +var rec3 = TestRecord{3, "ccc"} var rec1_expect, _ = json.Marshal(rec1) var rec2_expect, _ = json.Marshal(rec2) +var rec3_expect, _ = json.Marshal(rec3) func cleanup() { db.DeleteAllRecords(dbname) @@ -68,7 +70,6 @@ func TestMongoDBGetNextErrorWhenEmptyCollection(t *testing.T) { func TestMongoDBGetNextErrorWhenRecordNotThereYet(t *testing.T) { db.Connect(dbaddress) - db.databases = append(db.databases, dbname) defer cleanup() db.InsertRecord(dbname, &rec2) _, err := db.GetNextRecord(dbname) @@ -158,7 +159,7 @@ func TestMongoDBGetRecordByID(t *testing.T) { db.Connect(dbaddress) defer cleanup() db.InsertRecord(dbname, &rec1) - res, err := db.GetRecordByID(dbname, 1) + res, err := db.GetRecordByID(dbname, 1, true) assert.Nil(t, err) assert.Equal(t, string(rec1_expect), string(res)) } @@ -167,7 +168,62 @@ func TestMongoDBGetRecordByIDFails(t *testing.T) { db.Connect(dbaddress) defer cleanup() db.InsertRecord(dbname, &rec1) - _, err := db.GetRecordByID(dbname, 2) + _, err := db.GetRecordByID(dbname, 2, true) assert.Equal(t, utils.StatusNoData, err.(*DBError).Code) assert.Equal(t, "{\"id\":2}", err.Error()) } + +func TestMongoDBGetRecordNext(t *testing.T) { + db.Connect(dbaddress) + defer cleanup() + db.InsertRecord(dbname, &rec1) + res, err := db.GetRecordFromDb(dbname, "next", 0) + assert.Nil(t, err) + assert.Equal(t, string(rec1_expect), string(res)) +} + +func TestMongoDBGetRecordID(t *testing.T) { + db.Connect(dbaddress) + defer cleanup() + db.InsertRecord(dbname, &rec1) + res, err := db.GetRecordFromDb(dbname, "id", 1) + assert.Nil(t, err) + assert.Equal(t, string(rec1_expect), string(res)) +} + +func TestMongoDBWrongOp(t *testing.T) { + db.Connect(dbaddress) + defer cleanup() + db.InsertRecord(dbname, &rec1) + _, err := db.GetRecordFromDb(dbname, "bla", 0) + assert.NotNil(t, err) +} + +func TestMongoDBGetRecordLast(t *testing.T) { + db.Connect(dbaddress) + defer cleanup() + db.InsertRecord(dbname, &rec1) + db.InsertRecord(dbname, &rec2) + + res, err := db.GetRecordFromDb(dbname, "last", 0) + assert.Nil(t, err) + assert.Equal(t, string(rec2_expect), string(res)) +} + +func TestMongoDBGetNextAfterGetLastCorrect(t *testing.T) { + db.Connect(dbaddress) + defer cleanup() + db.InsertRecord(dbname, &rec1) + db.InsertRecord(dbname, &rec2) + + res, err := db.GetRecordFromDb(dbname, "last", 0) + assert.Nil(t, err) + assert.Equal(t, string(rec2_expect), string(res)) + + db.InsertRecord(dbname, &rec3) + + res, err = db.GetRecordFromDb(dbname, "next", 0) + assert.Nil(t, err) + assert.Equal(t, string(rec3_expect), string(res)) + +} diff --git a/broker/src/asapo_broker/server/get_id.go b/broker/src/asapo_broker/server/get_id.go index f66d61970091d8429d6cc6640315563917322d1c..adffdf262ff5fc9ea157990d616e9f624ef50a4b 100644 --- a/broker/src/asapo_broker/server/get_id.go +++ b/broker/src/asapo_broker/server/get_id.go @@ -1,8 +1,6 @@ package server import ( - "asapo_common/logger" - "asapo_common/utils" "github.com/gorilla/mux" "net/http" "strconv" @@ -19,37 +17,10 @@ func extractRequestParametersID(r *http.Request) (int, bool) { } func routeGetByID(w http.ResponseWriter, r *http.Request) { - r.Header.Set("Content-type", "application/json") - db_name, ok := extractRequestParameters(r) - if !ok { - w.WriteHeader(http.StatusBadRequest) - return - } id, ok := extractRequestParametersID(r) if !ok { w.WriteHeader(http.StatusBadRequest) return } - - if err := testAuth(r, db_name); err != nil { - writeAuthAnswer(w, "get id", db_name, err.Error()) - return - } - - answer, code := getRecordByID(db_name, id) - w.WriteHeader(code) - w.Write(answer) -} - -func getRecordByID(db_name string, id int) (answer []byte, code int) { - db_new := db.Copy() - defer db_new.Close() - statistics.IncreaseCounter() - answer, err := db_new.GetRecordByID(db_name, id) - log_str := "processing get id request in " + db_name + " at " + settings.BrokerDbAddress - if err != nil { - return returnError(err, log_str) - } - logger.Debug(log_str) - return answer, utils.StatusOK + getImage(w, r, "id", id) } diff --git a/broker/src/asapo_broker/server/get_id_test.go b/broker/src/asapo_broker/server/get_id_test.go index 0e18c932ad0f605c613dce336a1236c9dce1c6f3..dff12942c66fd9f5874e25c67669769624595612 100644 --- a/broker/src/asapo_broker/server/get_id_test.go +++ b/broker/src/asapo_broker/server/get_id_test.go @@ -3,8 +3,6 @@ package server import ( "asapo_broker/database" "asapo_common/logger" - "asapo_common/utils" - "errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" @@ -46,30 +44,12 @@ func TestGetIDTestSuite(t *testing.T) { suite.Run(t, new(GetIDTestSuite)) } -func (suite *GetIDTestSuite) TestGetIDWithWrongDatabaseName() { - suite.mock_db.On("GetRecordByID", expectedBeamtimeId, 1).Return([]byte(""), - &database.DBError{utils.StatusWrongInput, ""}) - - logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get id request in"))) - - w := doRequest("/database/" + expectedBeamtimeId + "/1" + correctTokenSuffix) - - suite.Equal(http.StatusBadRequest, w.Code, "wrong database name") -} - -func (suite *GetIDTestSuite) TestGetIDWithInternalDBError() { - suite.mock_db.On("GetRecordByID", expectedBeamtimeId, 1).Return([]byte(""), errors.New("")) - logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get id request in"))) - - w := doRequest("/database/" + expectedBeamtimeId + "/1" + correctTokenSuffix) - suite.Equal(http.StatusInternalServerError, w.Code, "internal error") -} - -func (suite *GetIDTestSuite) TestGetIDOK() { - suite.mock_db.On("GetRecordByID", expectedBeamtimeId, 1).Return([]byte("Hello"), nil) - logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get id request in"))) +func (suite *GetIDTestSuite) TestGetIdCallsCorrectRoutine() { + suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "id", 1).Return([]byte("Hello"), nil) + logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get id request"))) + ExpectCopyClose(suite.mock_db) w := doRequest("/database/" + expectedBeamtimeId + "/1" + correctTokenSuffix) - suite.Equal(http.StatusOK, w.Code, "GetID OK") + suite.Equal(http.StatusOK, w.Code, "GetImage OK") suite.Equal("Hello", string(w.Body.Bytes()), "GetID sends data") } diff --git a/broker/src/asapo_broker/server/get_image.go b/broker/src/asapo_broker/server/get_image.go new file mode 100644 index 0000000000000000000000000000000000000000..79f1ceaae687fe0d3deb376432d78e6e30eba8f6 --- /dev/null +++ b/broker/src/asapo_broker/server/get_image.go @@ -0,0 +1,60 @@ +package server + +import ( + "asapo_broker/database" + "asapo_common/logger" + "asapo_common/utils" + "github.com/gorilla/mux" + "net/http" +) + +func extractRequestParameters(r *http.Request) (string, bool) { + vars := mux.Vars(r) + db_name, ok := vars["dbname"] + return db_name, ok +} + +func getImage(w http.ResponseWriter, r *http.Request, op string, id int) { + r.Header.Set("Content-type", "application/json") + db_name, ok := extractRequestParameters(r) + if !ok { + w.WriteHeader(http.StatusBadRequest) + return + } + + if err := testAuth(r, db_name); err != nil { + writeAuthAnswer(w, "get "+op, db_name, err.Error()) + return + } + + answer, code := getRecord(db_name, op, id) + w.WriteHeader(code) + w.Write(answer) +} + +func returnError(err error, log_str string) (answer []byte, code int) { + err_db, ok := err.(*database.DBError) + code = utils.StatusError + if ok { + code = err_db.Code + } + if code != utils.StatusNoData { + logger.Error(log_str + " - " + err.Error()) + } else { + logger.Debug(log_str + " - " + err.Error()) + } + return []byte(err.Error()), code +} + +func getRecord(db_name string, op string, id int) (answer []byte, code int) { + db_new := db.Copy() + defer db_new.Close() + statistics.IncreaseCounter() + answer, err := db_new.GetRecordFromDb(db_name, op, id) + log_str := "processing get " + op + " request in " + db_name + " at " + settings.BrokerDbAddress + if err != nil { + return returnError(err, log_str) + } + logger.Debug(log_str) + return answer, utils.StatusOK +} diff --git a/broker/src/asapo_broker/server/get_image_test.go b/broker/src/asapo_broker/server/get_image_test.go new file mode 100644 index 0000000000000000000000000000000000000000..cd885e7e6cb402cd8df6c4e3df08c25713310821 --- /dev/null +++ b/broker/src/asapo_broker/server/get_image_test.go @@ -0,0 +1,134 @@ +package server + +import ( + "asapo_broker/database" + "asapo_common/logger" + "asapo_common/utils" + "errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +var correctTokenSuffix, wrongTokenSuffix, suffixWithWrongToken, expectedBeamtimeId string + +func prepareTestAuth() { + expectedBeamtimeId = "beamtime_id" + auth = utils.NewHMACAuth("secret") + token, err := auth.GenerateToken(&expectedBeamtimeId) + if err != nil { + panic(err) + } + correctTokenSuffix = "?token=" + token + wrongTokenSuffix = "?blablabla=aa" + suffixWithWrongToken = "?token=blabla" +} + +type request struct { + path string + cmd string + answer int + message string +} + +func containsMatcher(substrings ...string) func(str string) bool { + return func(str string) bool { + for _, substr := range substrings { + if !strings.Contains(str, substr) { + return false + } + } + return true + } +} + +func doRequest(path string) *httptest.ResponseRecorder { + mux := utils.NewRouter(listRoutes) + req, _ := http.NewRequest("GET", path, nil) + w := httptest.NewRecorder() + mux.ServeHTTP(w, req) + return w +} + +func TestGetImageWithoutDatabaseName(t *testing.T) { + w := doRequest("/database/next") + assert.Equal(t, http.StatusNotFound, w.Code, "no database name") +} + +func ExpectCopyClose(mock_db *database.MockedDatabase) { + mock_db.On("Copy").Return(mock_db) + mock_db.On("Close").Return() +} + +type GetImageTestSuite struct { + suite.Suite + mock_db *database.MockedDatabase +} + +func (suite *GetImageTestSuite) SetupTest() { + statistics.Reset() + suite.mock_db = new(database.MockedDatabase) + db = suite.mock_db + prepareTestAuth() + logger.SetMockLog() +} + +func (suite *GetImageTestSuite) TearDownTest() { + assertExpectations(suite.T(), suite.mock_db) + logger.UnsetMockLog() + db = nil +} + +func TestGetImageTestSuite(t *testing.T) { + suite.Run(t, new(GetImageTestSuite)) +} + +func (suite *GetImageTestSuite) TestGetImageWithWrongToken() { + logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong token"))) + + w := doRequest("/database/" + expectedBeamtimeId + "/next" + suffixWithWrongToken) + + suite.Equal(http.StatusUnauthorized, w.Code, "wrong token") +} + +func (suite *GetImageTestSuite) TestGetImageWithNoToken() { + logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("cannot extract"))) + + w := doRequest("/database/" + expectedBeamtimeId + "/next" + wrongTokenSuffix) + + suite.Equal(http.StatusUnauthorized, w.Code, "no token") +} + +func (suite *GetImageTestSuite) TestGetImageWithWrongDatabaseName() { + suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "next", 0).Return([]byte(""), + &database.DBError{utils.StatusWrongInput, ""}) + + logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get next request"))) + ExpectCopyClose(suite.mock_db) + + w := doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix) + + suite.Equal(http.StatusBadRequest, w.Code, "wrong database name") +} + +func (suite *GetImageTestSuite) TestGetImageWithInternalDBError() { + suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "next", 0).Return([]byte(""), errors.New("")) + logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get next request"))) + ExpectCopyClose(suite.mock_db) + + w := doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix) + suite.Equal(http.StatusInternalServerError, w.Code, "internal error") +} + +func (suite *GetImageTestSuite) TestGetImageAddsCounter() { + suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "next", 0).Return([]byte("Hello"), nil) + logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get next request in "+expectedBeamtimeId))) + ExpectCopyClose(suite.mock_db) + + doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix) + suite.Equal(1, statistics.GetCounter(), "GetImage increases counter") +} diff --git a/broker/src/asapo_broker/server/get_last.go b/broker/src/asapo_broker/server/get_last.go new file mode 100644 index 0000000000000000000000000000000000000000..19b270b58e5968088f6a9f9155448bcd795c33bc --- /dev/null +++ b/broker/src/asapo_broker/server/get_last.go @@ -0,0 +1,9 @@ +package server + +import ( + "net/http" +) + +func routeGetLast(w http.ResponseWriter, r *http.Request) { + getImage(w, r, "last", 0) +} diff --git a/broker/src/asapo_broker/server/get_last_test.go b/broker/src/asapo_broker/server/get_last_test.go new file mode 100644 index 0000000000000000000000000000000000000000..05d03460d73b503fb7cc1e2aef4979433452ab40 --- /dev/null +++ b/broker/src/asapo_broker/server/get_last_test.go @@ -0,0 +1,43 @@ +package server + +import ( + "asapo_broker/database" + "asapo_common/logger" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "net/http" + "testing" +) + +type GetLastTestSuite struct { + suite.Suite + mock_db *database.MockedDatabase +} + +func (suite *GetLastTestSuite) SetupTest() { + statistics.Reset() + suite.mock_db = new(database.MockedDatabase) + db = suite.mock_db + prepareTestAuth() + logger.SetMockLog() +} + +func (suite *GetLastTestSuite) TearDownTest() { + assertExpectations(suite.T(), suite.mock_db) + logger.UnsetMockLog() + db = nil +} + +func TestGetLastTestSuite(t *testing.T) { + suite.Run(t, new(GetLastTestSuite)) +} + +func (suite *GetLastTestSuite) TestGetLastCallsCorrectRoutine() { + suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "last", 0).Return([]byte("Hello"), nil) + logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get last request"))) + ExpectCopyClose(suite.mock_db) + + w := doRequest("/database/" + expectedBeamtimeId + "/last" + correctTokenSuffix) + suite.Equal(http.StatusOK, w.Code, "GetLast OK") + suite.Equal("Hello", string(w.Body.Bytes()), "GetLast sends data") +} diff --git a/broker/src/asapo_broker/server/get_next.go b/broker/src/asapo_broker/server/get_next.go index 5a42c3044238600655979d9919491293595c5c1a..661555bfecaa93152c39fcf96578aa6675d91908 100644 --- a/broker/src/asapo_broker/server/get_next.go +++ b/broker/src/asapo_broker/server/get_next.go @@ -1,60 +1,9 @@ package server import ( - "asapo_broker/database" - "asapo_common/logger" - "asapo_common/utils" - "github.com/gorilla/mux" "net/http" ) -func extractRequestParameters(r *http.Request) (string, bool) { - vars := mux.Vars(r) - db_name, ok := vars["dbname"] - return db_name, ok -} - func routeGetNext(w http.ResponseWriter, r *http.Request) { - r.Header.Set("Content-type", "application/json") - db_name, ok := extractRequestParameters(r) - if !ok { - w.WriteHeader(http.StatusBadRequest) - return - } - - if err := testAuth(r, db_name); err != nil { - writeAuthAnswer(w, "get next", db_name, err.Error()) - return - } - - answer, code := getNextRecord(db_name) - w.WriteHeader(code) - w.Write(answer) -} - -func returnError(err error, log_str string) (answer []byte, code int) { - err_db, ok := err.(*database.DBError) - code = utils.StatusError - if ok { - code = err_db.Code - } - if code != utils.StatusNoData { - logger.Error(log_str + " - " + err.Error()) - } else { - logger.Debug(log_str + " - " + err.Error()) - } - return []byte(err.Error()), code -} - -func getNextRecord(db_name string) (answer []byte, code int) { - db_new := db.Copy() - defer db_new.Close() - statistics.IncreaseCounter() - answer, err := db_new.GetNextRecord(db_name) - log_str := "processing get next request in " + db_name + " at " + settings.BrokerDbAddress - if err != nil { - return returnError(err, log_str) - } - logger.Debug(log_str) - return answer, utils.StatusOK + getImage(w, r, "next", 0) } diff --git a/broker/src/asapo_broker/server/get_next_test.go b/broker/src/asapo_broker/server/get_next_test.go index 72693797db667131bbd22b823e38b6a4b56d4e3c..04c681c61666d3418dcee1efc7ef3f7924279c25 100644 --- a/broker/src/asapo_broker/server/get_next_test.go +++ b/broker/src/asapo_broker/server/get_next_test.go @@ -3,67 +3,12 @@ package server import ( "asapo_broker/database" "asapo_common/logger" - "asapo_common/utils" - "errors" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" "net/http" - "net/http/httptest" - "strings" "testing" ) -var correctTokenSuffix, wrongTokenSuffix, suffixWithWrongToken, expectedBeamtimeId string - -func prepareTestAuth() { - expectedBeamtimeId = "beamtime_id" - auth = utils.NewHMACAuth("secret") - token, err := auth.GenerateToken(&expectedBeamtimeId) - if err != nil { - panic(err) - } - correctTokenSuffix = "?token=" + token - wrongTokenSuffix = "?blablabla=aa" - suffixWithWrongToken = "?token=blabla" -} - -type request struct { - path string - cmd string - answer int - message string -} - -func containsMatcher(substrings ...string) func(str string) bool { - return func(str string) bool { - for _, substr := range substrings { - if !strings.Contains(str, substr) { - return false - } - } - return true - } -} - -func doRequest(path string) *httptest.ResponseRecorder { - mux := utils.NewRouter(listRoutes) - req, _ := http.NewRequest("GET", path, nil) - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - return w -} - -func TestGetNextWithoutDatabaseName(t *testing.T) { - w := doRequest("/database/next") - assert.Equal(t, http.StatusNotFound, w.Code, "no database name") -} - -func ExpectCopyClose(mock_db *database.MockedDatabase) { - mock_db.On("Copy").Return(mock_db) - mock_db.On("Close").Return() -} - type GetNextTestSuite struct { suite.Suite mock_db *database.MockedDatabase @@ -87,45 +32,8 @@ func TestGetNextTestSuite(t *testing.T) { suite.Run(t, new(GetNextTestSuite)) } -func (suite *GetNextTestSuite) TestGetNextWithWrongToken() { - logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong token"))) - - w := doRequest("/database/" + expectedBeamtimeId + "/next" + suffixWithWrongToken) - - suite.Equal(http.StatusUnauthorized, w.Code, "wrong token") -} - -func (suite *GetNextTestSuite) TestGetNextWithNoToken() { - logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("cannot extract"))) - - w := doRequest("/database/" + expectedBeamtimeId + "/next" + wrongTokenSuffix) - - suite.Equal(http.StatusUnauthorized, w.Code, "no token") -} - -func (suite *GetNextTestSuite) TestGetNextWithWrongDatabaseName() { - suite.mock_db.On("GetNextRecord", expectedBeamtimeId).Return([]byte(""), - &database.DBError{utils.StatusWrongInput, ""}) - - logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get next request"))) - ExpectCopyClose(suite.mock_db) - - w := doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix) - - suite.Equal(http.StatusBadRequest, w.Code, "wrong database name") -} - -func (suite *GetNextTestSuite) TestGetNextWithInternalDBError() { - suite.mock_db.On("GetNextRecord", expectedBeamtimeId).Return([]byte(""), errors.New("")) - logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("get next request"))) - ExpectCopyClose(suite.mock_db) - - w := doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix) - suite.Equal(http.StatusInternalServerError, w.Code, "internal error") -} - -func (suite *GetNextTestSuite) TestGetNextWithGoodDatabaseName() { - suite.mock_db.On("GetNextRecord", expectedBeamtimeId).Return([]byte("Hello"), nil) +func (suite *GetNextTestSuite) TestGetNextCallsCorrectRoutine() { + suite.mock_db.On("GetRecordFromDb", expectedBeamtimeId, "next", 0).Return([]byte("Hello"), nil) logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get next request"))) ExpectCopyClose(suite.mock_db) @@ -133,12 +41,3 @@ func (suite *GetNextTestSuite) TestGetNextWithGoodDatabaseName() { suite.Equal(http.StatusOK, w.Code, "GetNext OK") suite.Equal("Hello", string(w.Body.Bytes()), "GetNext sends data") } - -func (suite *GetNextTestSuite) TestGetNextAddsCounter() { - suite.mock_db.On("GetNextRecord", expectedBeamtimeId).Return([]byte("Hello"), nil) - logger.MockLog.On("Debug", mock.MatchedBy(containsMatcher("get next request in "+expectedBeamtimeId))) - ExpectCopyClose(suite.mock_db) - - doRequest("/database/" + expectedBeamtimeId + "/next" + correctTokenSuffix) - suite.Equal(1, statistics.GetCounter(), "GetNext increases counter") -} diff --git a/broker/src/asapo_broker/server/listroutes.go b/broker/src/asapo_broker/server/listroutes.go index ceee311d46043ccbaca28e037b07c4aa97457d3e..23c73d9daa12e6363ee14613cc354d293840be72 100644 --- a/broker/src/asapo_broker/server/listroutes.go +++ b/broker/src/asapo_broker/server/listroutes.go @@ -11,6 +11,12 @@ var listRoutes = utils.Routes{ "/database/{dbname}/next", routeGetNext, }, + utils.Route{ + "GetLast", + "Get", + "/database/{dbname}/last", + routeGetLast, + }, utils.Route{ "GetID", "Get", diff --git a/tests/automatic/broker/CMakeLists.txt b/tests/automatic/broker/CMakeLists.txt index 6f1685c7d12bf036a9fa6f126b357fd962d2b954..37420e25280cc15c84dddb7d4b1159f6eab7d0b1 100644 --- a/tests/automatic/broker/CMakeLists.txt +++ b/tests/automatic/broker/CMakeLists.txt @@ -1,4 +1,6 @@ add_subdirectory(get_next) +add_subdirectory(get_last) + add_subdirectory(read_config) if (UNIX) diff --git a/tests/automatic/broker/get_last/CMakeLists.txt b/tests/automatic/broker/get_last/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c085d239c2fcc5a38422d6ee6f8300e5cba6994 --- /dev/null +++ b/tests/automatic/broker/get_last/CMakeLists.txt @@ -0,0 +1,10 @@ +set(TARGET_NAME asapo-broker) + +################################ +# Testing +################################ +configure_file(${CMAKE_SOURCE_DIR}/tests/automatic/settings/broker_settings.json settings.json COPYONLY) +configure_file(${CMAKE_SOURCE_DIR}/tests/automatic/settings/broker_secret.key broker_secret.key COPYONLY) + +add_script_test("${TARGET_NAME}-getlast" "$<TARGET_PROPERTY:${TARGET_NAME},EXENAME> $<TARGET_PROPERTY:asapo,EXENAME>" nomem + ) diff --git a/tests/automatic/broker/get_last/check_linux.sh b/tests/automatic/broker/get_last/check_linux.sh new file mode 100644 index 0000000000000000000000000000000000000000..4f0781386f675ce4f5567b3645461f7c623a0064 --- /dev/null +++ b/tests/automatic/broker/get_last/check_linux.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +database_name=data + +set -e + +trap Cleanup EXIT + +Cleanup() { + echo cleanup + echo "db.dropDatabase()" | mongo ${database_name} + kill -9 $brokerid +} + +echo "db.data.insert({"_id":2})" | mongo ${database_name} +echo "db.data.insert({"_id":1})" | mongo ${database_name} + +token=`$2 token -secret broker_secret.key data` + +$1 -config settings.json & + +sleep 0.3 +brokerid=`echo $!` + + +curl -v --silent 127.0.0.1:5005/database/data/last?token=$token --stderr - + +curl -v --silent 127.0.0.1:5005/database/data/last?token=$token --stderr - | grep '"_id":2' +curl -v --silent 127.0.0.1:5005/database/data/last?token=$token --stderr - | grep '"_id":2' + +echo "db.data.insert({"_id":3})" | mongo ${database_name} + +curl -v --silent 127.0.0.1:5005/database/data/last?token=$token --stderr - | grep '"_id":3' + +echo "db.data.insert({"_id":4})" | mongo ${database_name} + +curl -v --silent 127.0.0.1:5005/database/data/next?token=$token --stderr - | grep '"_id":4' +curl -v --silent 127.0.0.1:5005/database/data/last?token=$token --stderr - | grep '"_id":4' \ No newline at end of file diff --git a/tests/automatic/broker/get_last/check_windows.bat b/tests/automatic/broker/get_last/check_windows.bat new file mode 100644 index 0000000000000000000000000000000000000000..71f1a56ed36dd3b80532d460a2182cc219f208e2 --- /dev/null +++ b/tests/automatic/broker/get_last/check_windows.bat @@ -0,0 +1,40 @@ +SET database_name=data +SET mongo_exe="c:\Program Files\MongoDB\Server\3.6\bin\mongo.exe" + +echo db.data.insert({"_id":1}) | %mongo_exe% %database_name% || goto :error +echo db.data.insert({"_id":2}) | %mongo_exe% %database_name% || goto :error + +set full_name="%1" +set short_name="%~nx1" + +"%2" token -secret broker_secret.key data > token +set /P token=< token + + + +start /B "" "%full_name%" -config settings.json + +ping 1.0.0.0 -n 1 -w 100 > nul + +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/last?token=%token% --stderr - | findstr /c:\"_id\":2 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/last?token=%token% --stderr - | findstr /c:\"_id\":2 || goto :error + +echo db.data.insert({"_id":3}) | %mongo_exe% %database_name% || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/last?token=%token% --stderr - | findstr /c:\"_id\":3 || goto :error + +echo db.data.insert({"_id":4}) | %mongo_exe% %database_name% || goto :error + +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/next?token=%token% --stderr - | findstr /c:\"_id\":3 || goto :error +C:\Curl\curl.exe -v --silent 127.0.0.1:5005/database/data/last?token=%token% --stderr - | findstr /c:\"_id\":3 || goto :error + + +goto :clean + +:error +call :clean +exit /b 1 + +:clean +Taskkill /IM "%short_name%" /F +echo db.dropDatabase() | %mongo_exe% %database_name% +del /f token \ No newline at end of file diff --git a/worker/api/cpp/include/worker/data_broker.h b/worker/api/cpp/include/worker/data_broker.h index dd8eb0c794b8c0b60942c48e34635e0f540eca9e..d7eb5ed592e633af0ce1d0094a54f7e3a7aeee9f 100644 --- a/worker/api/cpp/include/worker/data_broker.h +++ b/worker/api/cpp/include/worker/data_broker.h @@ -40,12 +40,12 @@ class DataBroker { \return Error if both pointers are nullptr or data cannot be read, WorkerErrorCode::OK otherwise. */ virtual Error GetNext(FileInfo* info, FileData* data) = 0; - //! Receive last available image. - /*! - \param info - where to store image metadata. Can be set to nullptr only image data is needed. - \param data - where to store image data. Can be set to nullptr only image metadata is needed. - \return Error if both pointers are nullptr or data cannot be read, WorkerErrorCode::OK otherwise. - */ + //! Receive last available image. + /*! + \param info - where to store image metadata. Can be set to nullptr only image data is needed. + \param data - where to store image data. Can be set to nullptr only image metadata is needed. + \return Error if both pointers are nullptr or data cannot be read, WorkerErrorCode::OK otherwise. + */ virtual Error GetLast(FileInfo* info, FileData* data) = 0; virtual ~DataBroker() = default; // needed for unique_ptr to delete itself }; diff --git a/worker/api/cpp/src/folder_data_broker.cpp b/worker/api/cpp/src/folder_data_broker.cpp index 1b9d7264ce171b217a32f23c4cfd5ec59bc369aa..35a4fb096f3dc4fc0bffb1805df536b68beb2075 100644 --- a/worker/api/cpp/src/folder_data_broker.cpp +++ b/worker/api/cpp/src/folder_data_broker.cpp @@ -42,7 +42,7 @@ Error FolderDataBroker::CanGetData(FileInfo* info, FileData* data, uint64_t nfil return nullptr; } -Error FolderDataBroker::GetFileByIndex(uint64_t nfile_to_get,FileInfo* info, FileData* data) { +Error FolderDataBroker::GetFileByIndex(uint64_t nfile_to_get, FileInfo* info, FileData* data) { auto err = CanGetData(info, data, nfile_to_get); if (err != nullptr) { return err; @@ -67,12 +67,12 @@ Error FolderDataBroker::GetNext(FileInfo* info, FileData* data) { uint64_t nfile_to_get = ++current_file_; mutex_.unlock(); - return GetFileByIndex(nfile_to_get,info,data); + return GetFileByIndex(nfile_to_get, info, data); } Error FolderDataBroker::GetLast(FileInfo* info, FileData* data) { - uint64_t nfile_to_get = filelist_.size()-1; - return GetFileByIndex(nfile_to_get,info,data); + uint64_t nfile_to_get = filelist_.size() - 1; + return GetFileByIndex(nfile_to_get, info, data); } } diff --git a/worker/api/cpp/src/folder_data_broker.h b/worker/api/cpp/src/folder_data_broker.h index a7b43f73ad5838b8e47af44606e3a6eb970895c4..cbf2005a86f67eac1c049544d6ae49cb11ad6284 100644 --- a/worker/api/cpp/src/folder_data_broker.h +++ b/worker/api/cpp/src/folder_data_broker.h @@ -25,7 +25,7 @@ class FolderDataBroker final : public asapo::DataBroker { int current_file_; FileInfos filelist_; Error CanGetData(FileInfo* info, FileData* data, uint64_t nfile) const noexcept; - Error GetFileByIndex(uint64_t nfile_to_get,FileInfo* info, FileData* data); + Error GetFileByIndex(uint64_t nfile_to_get, FileInfo* info, FileData* data); std::mutex mutex_; }; diff --git a/worker/api/cpp/src/server_data_broker.cpp b/worker/api/cpp/src/server_data_broker.cpp index 01469e35066451c45786e494e3ee348cc0951586..aff8b3dcf522e664d95f8883b8b2f6efba0d3ab6 100644 --- a/worker/api/cpp/src/server_data_broker.cpp +++ b/worker/api/cpp/src/server_data_broker.cpp @@ -141,19 +141,19 @@ Error ServerDataBroker::GetFileInfoFromServer(FileInfo* info, GetImageServerOper } Error ServerDataBroker::GetNext(FileInfo* info, FileData* data) { - return GetImageFromServer(GetImageServerOperation::GetNext,info,data); + return GetImageFromServer(GetImageServerOperation::GetNext, info, data); } Error ServerDataBroker::GetLast(FileInfo* info, FileData* data) { - return GetImageFromServer(GetImageServerOperation::GetLast,info,data); + return GetImageFromServer(GetImageServerOperation::GetLast, info, data); } std::string ServerDataBroker::OpToUriCmd(GetImageServerOperation op) { switch (op) { - case GetImageServerOperation::GetNext: - return "next"; - case GetImageServerOperation::GetLast: - return "last"; + case GetImageServerOperation::GetNext: + return "next"; + case GetImageServerOperation::GetLast: + return "last"; } return ""; } diff --git a/worker/api/cpp/src/server_data_broker.h b/worker/api/cpp/src/server_data_broker.h index a1e6fe4bd2f3133f1692d0263c64685681258b27..cc99eb51fb47c4075c1017371f0cce965943deee 100644 --- a/worker/api/cpp/src/server_data_broker.h +++ b/worker/api/cpp/src/server_data_broker.h @@ -11,8 +11,8 @@ namespace asapo { Error HttpCodeToWorkerError(const HttpCode& code); enum class GetImageServerOperation { - GetNext, - GetLast + GetNext, + GetLast }; class ServerDataBroker final : public asapo::DataBroker { @@ -22,7 +22,7 @@ class ServerDataBroker final : public asapo::DataBroker { Error GetNext(FileInfo* info, FileData* data) override; Error GetLast(FileInfo* info, FileData* data) override; - void SetTimeout(uint64_t timeout_ms) override; + void SetTimeout(uint64_t timeout_ms) override; std::unique_ptr<IO> io__; // modified in testings to mock system calls,otherwise do not touch std::unique_ptr<HttpClient> httpclient__; private: diff --git a/worker/api/cpp/unittests/test_server_broker.cpp b/worker/api/cpp/unittests/test_server_broker.cpp index 395c3cbba8779586b243a8b10bba06b853f3b4ea..14538967a72bb6fbedce751433ad0ccc9c8978b7 100644 --- a/worker/api/cpp/unittests/test_server_broker.cpp +++ b/worker/api/cpp/unittests/test_server_broker.cpp @@ -119,9 +119,9 @@ TEST_F(ServerDataBrokerTests, GetLastUsesCorrectUri) { EXPECT_CALL(mock_http_client, Get_t(expected_broker_uri + "/database/beamtime_id/last?token=" + expected_token, _, _)).WillOnce(DoAll( - SetArgPointee<1>(HttpCode::OK), - SetArgPointee<2>(nullptr), - Return(""))); + SetArgPointee<1>(HttpCode::OK), + SetArgPointee<2>(nullptr), + Return(""))); data_broker->GetLast(&info, nullptr); }