Beispiel #1
0
//
// POST /reservations/{key}
//
// Wait for {key} to be available (ignore cases where the client times out), then acquire a lock on it (and its value).
//
func (s *Server) GetAndLock(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	rawKey, exists := vars["key"]
	if !exists {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	s.logger.Printf("key: %v, %v", rawKey, s.mdb)

	key := memdb.Key(rawKey)
	lockId, value, err := s.mdb.GetAndLock(key)
	s.logger.Printf("lockId: %v, Value: %v, Err: %v", lockId, value, err)
	if err == memdb.ErrKeyNotFound {
		w.WriteHeader(http.StatusNotFound)
		return
	} else if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	jsonResponse := &LockValueResponse{LockId: string(lockId), Value: string(value)}
	s.logger.Printf("jsonResponse: %v", jsonResponse)

	body, err := json.Marshal(jsonResponse)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(body)
}
Beispiel #2
0
//
// PUT /values/{key}
//
// If {key} already exists, wait until it's available (ignore cases where the client times out) then acquire the lock on it.
// If it doesn't already exist, create it and immediately acquire the lock on it (that operation should never block).
//
func (s *Server) PutAndLock(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	// handle key var
	rawKey, exists := vars["key"]
	if !exists {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	key := memdb.Key(rawKey)

	// handle POST body
	rawValue, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	value := memdb.Value(rawValue)

	// store value into the memdb
	lockid := s.mdb.Put(key, value)

	// create response
	jsonResponse := &LockResponse{LockId: string(lockid)}
	body, err := json.Marshal(&jsonResponse)
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(body)
}
Beispiel #3
0
//
// POST /values/{key}/{lock_id}?release={true, false}
//
// Attempt to update the value of {key} to the value given in the POST body according to the following rules:
//
// If {key} doesn't exist, return 404 Not Found
// If {key} exists but {lock_id} doesn't identify the currently held lock, do no action and respond immediately with 401 Unauthorized.
// If {key} exists, {lock_id} identifies the currently held lock and release=true, set the new value, release the lock and invalidate {lock_id}. Return 204 No Content
// If {key} exists, {lock_id} identifies the currently held lock and release=false, set the new value but don't release the lock and keep {lock_id} value. Return 204 No Content
//
func (s *Server) Update(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	// handle key var
	rawKey, exists := vars["key"]
	if !exists {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	key := memdb.Key(rawKey)

	// handle lock_id var
	rawLockId, exists := vars["lock_id"]
	if !exists {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	lockId := memdb.LockID(rawLockId)

	// handle release query param
	release, err := strconv.ParseBool(vars["release"])
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// read POST Body
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// try to update...
	err = s.mdb.Update(lockId, key, memdb.Value(string(body)), release)
	if err == memdb.ErrKeyNotFound {
		w.WriteHeader(http.StatusNotFound)
		return

	} else if err == memdb.ErrLockIdNotFound {
		w.WriteHeader(http.StatusUnauthorized)
		return

	} else if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}
Beispiel #4
0
func TestRestServerUpdate(t *testing.T) {
	server := NewRestServer()
	// log := log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
	// server := NewRestServerWithLogger(log)

	// try to release unexists lock for unexists key
	rec0 := httptest.NewRecorder()
	req, err := http.NewRequest("POST", "http://memdb.devel/values/key0/1?release=true", strings.NewReader(""))
	assert.Nil(t, err)
	server.Router().ServeHTTP(rec0, req)
	assert.Equal(t, http.StatusNotFound, rec0.Code)

	// put new value and get lock
	rec2 := httptest.NewRecorder()
	req2, err2 := http.NewRequest("PUT", "http://memdb.devel/values/key0", strings.NewReader("value"))
	assert.Nil(t, err2)
	server.Router().ServeHTTP(rec2, req2)
	jr2 := &LockResponse{}
	assert.NoError(t, json.Unmarshal(rec2.Body.Bytes(), &jr2))
	assert.Equal(t, "1", jr2.LockId)
	v2, exists2 := server.mdb.DirectGet(memdb.Key("key0"))
	assert.True(t, exists2)
	assert.Equal(t, memdb.Value("value"), v2)

	// try to release unexists lock for exists key
	rec3 := httptest.NewRecorder()
	req3, err3 := http.NewRequest("POST", "http://memdb.devel/values/key0/2?release=true", strings.NewReader(""))
	assert.Nil(t, err3)
	server.Router().ServeHTTP(rec3, req3)
	assert.Equal(t, http.StatusUnauthorized, rec3.Code)

	// set new value for exists key and release lock
	rec4 := httptest.NewRecorder()
	req4, err4 := http.NewRequest("POST", "http://memdb.devel/values/key0/1?release=true", strings.NewReader("newValue"))
	assert.Nil(t, err4)
	server.Router().ServeHTTP(rec4, req4)
	assert.Equal(t, http.StatusNoContent, rec4.Code)
	v, exists := server.mdb.DirectGet(memdb.Key("key0"))
	assert.True(t, exists)
	assert.Equal(t, memdb.Value("newValue"), v)

	// check if lock was released...
	rec5 := httptest.NewRecorder()
	req5, err5 := http.NewRequest("POST", "http://memdb.devel/values/key0/1?release=false", strings.NewReader(""))
	assert.Nil(t, err5)
	server.Router().ServeHTTP(rec5, req5)
	assert.Equal(t, http.StatusUnauthorized, rec5.Code)

	// get new lock for exists key
	//server.router.HandleFunc("/reservations/{key}", http.HandlerFunc(server.GetAndLock)).Methods("POST")
	rec6 := httptest.NewRecorder()
	req6, err6 := http.NewRequest("POST", "http://memdb.devel/reservations/key0", strings.NewReader(""))
	assert.Nil(t, err6)
	server.Router().ServeHTTP(rec6, req6)
	assert.Equal(t, http.StatusOK, rec6.Code)
	jr6 := &LockValueResponse{}
	err6 = json.Unmarshal(rec6.Body.Bytes(), &jr6)
	assert.NoError(t, err6)
	assert.Equal(t, "2", jr6.LockId)
	assert.Equal(t, "newValue", jr6.Value)

	// update value but don't release lock
	rec7 := httptest.NewRecorder()
	req7, err7 := http.NewRequest("POST", "http://memdb.devel/values/key0/2?release=false", strings.NewReader("otherValue"))
	assert.Nil(t, err7)
	server.Router().ServeHTTP(rec7, req7)
	assert.Equal(t, http.StatusNoContent, rec7.Code)
	v7, exists7 := server.mdb.DirectGet(memdb.Key("key0"))
	assert.True(t, exists7)
	assert.Equal(t, memdb.Value("otherValue"), v7)

	// release lock
	rec8 := httptest.NewRecorder()
	req8, err8 := http.NewRequest("POST", "http://memdb.devel/values/key0/2?release=true", strings.NewReader("released"))
	assert.Nil(t, err8)
	server.Router().ServeHTTP(rec8, req8)
	assert.Equal(t, http.StatusNoContent, rec8.Code)
}