Beispiel #1
0
func TestUpdateValExistsInvalidLockRelease(t *testing.T) {
	data = DataStore{Entries: make(map[string]*Entry)}
	locks = LockStore{Locks: make(map[string]struct{})}
	testKey := randstr.New(5)
	testVal := randstr.New(10)
	testLockId := randstr.New(5)

	err := data.AddEntry(&Entry{Key: testKey, Value: testVal, LockId: testLockId})
	if err != nil {
		t.Error(err)
	}

	testdata := strings.NewReader(testVal)
	req, err := http.NewRequest("POST", fmt.Sprintf(postValUrl, testKey, "invalidlock", "true"), testdata)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()

	muxr.ServeHTTP(w, req)
	checkCode(t, http.StatusUnauthorized, w.Code)

	entry, err := data.GetEntry(testKey)
	if err != nil {
		t.Errorf("Error getting data entry from key: %s", err)
	}

	if !entry.IsLocked() {
		t.Error("Entry should be locked.")
	}

	if entry.GetValue() != testVal {
		t.Error("Expected data incorrect.")
	}
}
Beispiel #2
0
func TestReserveKeyExistsUnlockedTimeout(t *testing.T) {
	data = DataStore{Entries: make(map[string]*Entry)}
	locks = LockStore{Locks: make(map[string]struct{})}
	testKey := randstr.New(5)
	testVal := randstr.New(10)

	err := data.AddEntry(&Entry{Key: testKey, Value: testVal})
	if err != nil {
		t.Error(err)
	}

	req, err := http.NewRequest("POST", fmt.Sprintf(postResUrl, testKey), nil)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()

	muxr.ServeHTTP(w, req)
	checkCode(t, http.StatusOK, w.Code)

	val := make(map[string]string)
	rdata := w.Body.Bytes()

	err = json.Unmarshal(rdata, &val)
	if err != nil {
		t.Errorf("Unmarshal error: %s", err)
	}

	entry, err := data.GetEntry(testKey)
	if err != nil {
		t.Errorf("Error getting data entry from key: %s", err)
	}

	if !entry.IsLocked() {
		t.Error("Entry should be locked.")
	}

	if l, ok := val["lock_id"]; !ok {
		t.Error("Did not receive valid JSON data.")
	} else {
		if !entry.ValidLock(l) {
			t.Error("Received data should match expected LockId.")
		}
	}

	if l, ok := val["value"]; !ok {
		t.Error("Did not receive valid JSON data.")
	} else {
		if l != testVal {
			t.Error("Received data should match expected value.")
		}
	}
}
Beispiel #3
0
func newLockId() string {
	newid := randstr.New(5)
	logger.Debugf("New LockId generated: %s", newid)

	//Ensure we don't collide our LockId.
	for locks.LockExists(newid) {
		newid = randstr.New(5)
		logger.Debugf("Collision occured, new LockId generated: %s", newid)
	}

	return newid
}
Beispiel #4
0
func TestPutValNoExists(t *testing.T) {
	data = DataStore{Entries: make(map[string]*Entry)}
	locks = LockStore{Locks: make(map[string]struct{})}
	testKey := randstr.New(5)
	testVal := randstr.New(10)

	testdata := strings.NewReader(testVal)
	req, err := http.NewRequest("PUT", fmt.Sprintf(putValUrl, testKey), testdata)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()

	muxr.ServeHTTP(w, req)
	checkCode(t, http.StatusOK, w.Code)

	if !data.EntryExists(testKey) {
		t.Error("Data should exist.")
	}

	entry, err := data.GetEntry(testKey)
	if err != nil {
		t.Errorf("Error getting data entry from key: %s", err)
	}

	if !entry.IsLocked() {
		t.Error("Entry should be locked.")
	}

	if entry.GetValue() != testVal {
		t.Error("Expected data incorrect.")
	}

	val := make(map[string]string)
	rdata := w.Body.Bytes()

	err = json.Unmarshal(rdata, &val)
	if err != nil {
		t.Errorf("Unmarshal error: %s", err)
	}

	if l, ok := val["lock_id"]; !ok {
		t.Error("Did not receive valid JSON data.")
	} else {
		if !entry.ValidLock(l) {
			t.Error("Entry should be locked with expected LockId.")
		}
	}
}
Beispiel #5
0
func TestPutValExistsLocked(t *testing.T) {
	data = DataStore{Entries: make(map[string]*Entry)}
	locks = LockStore{Locks: make(map[string]struct{})}
	testKey := randstr.New(5)
	testVal := randstr.New(10)
	testLockId := randstr.New(5)

	err := data.AddEntry(&Entry{Key: testKey, Value: testVal, LockId: testLockId})
	if err != nil {
		t.Error(err)
	}

	testdata := strings.NewReader(testVal)
	req, err := http.NewRequest("PUT", fmt.Sprintf(putValUrl, testKey), testdata)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()

	muxr.ServeHTTP(w, req)
	checkCode(t, http.StatusRequestTimeout, w.Code)

	if !data.EntryExists(testKey) {
		t.Error("Data should exist.")
	}

	entry, err := data.GetEntry(testKey)
	if err != nil {
		t.Errorf("Error getting data entry from key: %s", err)
	}

	if !entry.IsLocked() {
		t.Error("Entry should be locked.")
	}

	if !entry.ValidLock(testLockId) {
		t.Error("Entry should be locked with expected LockId.")
	}

	if entry.GetValue() != testVal {
		t.Error("Expected data incorrect.")
	}
}
Beispiel #6
0
func reserveKey(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	logger.Infof("Received PUT request to /reservations/{key}, request id: %s", randstr.New(5))
	logger.Debugf("Received varaibles: %v", vars)

	//Check to see if we actually got a key.
	key, exists := vars["key"]
	if !exists {
		logger.Info("Invalid request, no key specified.")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	//Get the reference to the entry for the specified key.
	entry, err := data.GetEntry(key)
	if err != nil {
		logger.Infof("Invalid request, entry key not found: %s", key)
		w.WriteHeader(http.StatusNotFound)
		return
	}

	entry.Lock()
	defer entry.Unlock()

	newid := newLockId()

	//Check the LockId, if unlocked, set lock. If locked, acquire lock.
	if entry.SetLockId(newid) {
		logger.Debug("Set the lock successfully.")
	} else {
		//Looks like someone has it already, attempt an acquisition.
		err := AcquireLock(entry, time.Second*Config.App.TimeOut, newid)
		if err != nil {
			logger.Info(err)
			w.WriteHeader(http.StatusRequestTimeout)
			return
		}
		logger.Debug("Acquired the lock successfully.")
	}

	j, err := entry.GetJson()

	if err != nil {
		logger.Errorf("Error marshaling entry to json: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
	logger.Infof("Handled successful request for: %s", key)
}
Beispiel #7
0
func TestReserveKeyNoExists(t *testing.T) {
	data = DataStore{Entries: make(map[string]*Entry)}
	locks = LockStore{Locks: make(map[string]struct{})}
	testKey := randstr.New(5)

	req, err := http.NewRequest("POST", fmt.Sprintf(postResUrl, testKey), nil)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()
	muxr.ServeHTTP(w, req)
	checkCode(t, http.StatusNotFound, w.Code)
}
Beispiel #8
0
func TestUpdateValNoExists(t *testing.T) {
	data = DataStore{Entries: make(map[string]*Entry)}
	locks = LockStore{Locks: make(map[string]struct{})}
	testVal := randstr.New(10)

	testdata := strings.NewReader(testVal)
	req, err := http.NewRequest("POST", fmt.Sprintf(postValUrl, "invalidkey", "invalidlockid", "false"), testdata)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()

	muxr.ServeHTTP(w, req)
	checkCode(t, http.StatusNotFound, w.Code)
}
Beispiel #9
0
func TestReserveKeyExistsLockedAcquire(t *testing.T) {
	data = DataStore{Entries: make(map[string]*Entry)}
	locks = LockStore{Locks: make(map[string]struct{})}
	testKey := randstr.New(5)
	testVal := randstr.New(10)
	testLockId := randstr.New(5)

	req, err := http.NewRequest("POST", fmt.Sprintf(postResUrl, testKey), nil)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()

	err = data.AddEntry(&Entry{Key: testKey, Value: testVal, LockId: testLockId})
	if err != nil {
		t.Error(err)
	}

	if !data.EntryExists(testKey) {
		t.Error("Data should exist.")
	}

	entry, err := data.GetEntry(testKey)
	if err != nil {
		t.Errorf("Error getting data entry from key: %s", err)
	}

	tick := time.NewTicker(time.Millisecond * 100)
	go func() {

		if !entry.IsLocked() {
			t.Error("Entry should be locked.")
		}

		<-tick.C

		entry.UnsetLockId()
		if entry.IsLocked() {
			t.Error("Entry should no longer be locked.")
		}

		<-tick.C
	}()

	muxr.ServeHTTP(w, req)
	checkCode(t, http.StatusOK, w.Code)

	val := make(map[string]string)
	rdata := w.Body.Bytes()

	err = json.Unmarshal(rdata, &val)
	if err != nil {
		t.Errorf("Unmarshal error: %s", err)
	}

	if !entry.IsLocked() {
		t.Error("Entry should be locked.")
	}

	testLockId = entry.GetLockId()

	if l, ok := val["lock_id"]; !ok {
		t.Error("Did not receive valid JSON data.")
	} else {
		if !entry.ValidLock(l) {
			t.Error("Received data should match expected LockId.")
		}
	}

	if l, ok := val["value"]; !ok {
		t.Error("Did not receive valid JSON data.")
	} else {
		if l != entry.GetValue() {
			t.Error("Received data should match expected value.")
		}
	}
}
Beispiel #10
0
func TestPutValExistsLockedAcquire(t *testing.T) {
	data = DataStore{Entries: make(map[string]*Entry)}
	locks = LockStore{Locks: make(map[string]struct{})}
	testKey := randstr.New(5)
	testVal := randstr.New(10)
	testLockId := randstr.New(5)

	err := data.AddEntry(&Entry{Key: testKey, Value: testVal, LockId: testLockId})
	if err != nil {
		t.Error(err)
	}

	testNewVal := "NewValue"
	testdata := strings.NewReader(testNewVal)
	req, err := http.NewRequest("PUT", fmt.Sprintf(putValUrl, testKey), testdata)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()

	if !data.EntryExists(testKey) {
		t.Error("Data should exist.")
	}

	entry, err := data.GetEntry(testKey)
	if err != nil {
		t.Errorf("Error getting data entry from key: %s", err)
	}

	tick := time.NewTicker(time.Millisecond * 100)
	go func() {

		if !entry.IsLocked() {
			t.Error("Entry should be locked.")
		}

		if entry.GetValue() == testNewVal {
			t.Error("Data should still be incorrect before acquisition of lock.")
		}

		<-tick.C

		entry.UnsetLockId()
		if entry.IsLocked() {
			t.Error("Entry should no longer be locked.")
		}

		<-tick.C
	}()

	muxr.ServeHTTP(w, req)
	checkCode(t, http.StatusOK, w.Code)

	if !entry.IsLocked() {
		t.Error("Entry should be locked.")
	}

	if entry.GetValue() != testNewVal {
		t.Error("Expected data incorrect.")
	}

	tick.Stop()

	val := make(map[string]string)
	rdata := w.Body.Bytes()

	err = json.Unmarshal(rdata, &val)
	if err != nil {
		t.Errorf("Unmarshal error: %s", err)
	}

	if l, ok := val["lock_id"]; !ok {
		t.Error("Did not receive valid JSON data.")
	} else {
		testLockId = l
	}

	if !entry.ValidLock(testLockId) {
		t.Error("Entry should be locked with expected LockId.")
	}
}
Beispiel #11
0
func updateVal(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	logger.Infof("Received PUT request to /values/{key}/{lock_id}, request id: %s", randstr.New(5))
	logger.Debugf("Received varaibles: %v", vars)

	//Check to see if we actually got a key.
	key, exists := vars["key"]
	if !exists {
		logger.Info("Invalid request, no key specified.")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	//Get the reference to the entry.
	entry, err := data.GetEntry(key)
	if err != nil {
		logger.Infof("Invalid request, entry key not found: %s", key)
		w.WriteHeader(http.StatusNotFound)
		return
	}

	entry.Lock()
	defer entry.Unlock()

	//Check to make sure we got a LockId specified.
	lockid, exists := vars["lock_id"]
	if !exists {
		logger.Info("Invalid request, no lock_id specified.")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	//Parse the query value, treat an empty query value as if "false".
	rel := r.FormValue("release")
	release := false
	if rel == "true" {
		release = true
		logger.Debug("Release set to true.")
	} else if rel != "" && rel != "false" {
		logger.Infof("Invalid release query specified: %s", rel)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	//Check the LockId.
	logger.Debugf("Checking lock validity for entry: %s - LockId: %s", key, lockid)
	if !entry.ValidLock(lockid) {
		logger.Debugf("LockId does not match entry: %s - LockId: %s - Expected: %s", key, lockid, entry.GetLockId())
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	//If we made it here, it means we either didn't have a lock
	//or the correct LockId was specified.
	logger.Debug("LockId matches, reading new value.")

	//Get the new value.
	bytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		logger.Errorf("Error reading request body: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	entry.SetValue(string(bytes))
	logger.Info("Successfully set new submitted value.")
	w.WriteHeader(http.StatusNoContent)

	if release {
		logger.Infof("Removing lock from entry: %s", entry.GetKey())
		entry.UnsetLockId()
	}
	logger.Infof("Handled successful request for: %s", key)
}
Beispiel #12
0
func putVal(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	logger.Infof("Received PUT request to /values/{key}, request id: %s", randstr.New(5))
	logger.Debugf("Received varaibles: %v", vars)

	//Check to see if we actually got a key.
	key, exists := vars["key"]
	if !exists {
		logger.Info("Invalid request, no key specified.")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	//Get the reference to the entry if it exists.
	entry, err := data.GetEntry(key)
	if err != nil {
		logger.Infof("Generating new entry for key: %s", key)
		logger.Debugf("Received during GetEntry: %s", err)

		//Didn't exist, make a new one!
		entry = &Entry{Key: key}
		err = data.AddEntry(entry)
		if err != nil {
			logger.Debug(err)
		}
	}

	entry.Lock()
	defer entry.Unlock()

	logger.Debug("Reading request body... ")
	//Get the new value.
	bytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		logger.Errorf("Error occured reading request body: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	logger.Debugf("Received request body: %s", string(bytes))

	newid := newLockId()

	logger.Debug("Checking entry lock state.")

	//Check the LockId, if unlocked, set lock. If locked, acquire lock.
	if entry.SetLockId(newid) {
		logger.Debug("Set the lock successfully.")
	} else {
		//Looks like someone has it already, attempt an acquisition.
		err := AcquireLock(entry, time.Second*Config.App.TimeOut, newid)
		if err != nil {
			logger.Info(err)
			w.WriteHeader(http.StatusRequestTimeout)
			return
		}
		logger.Debug("Acquired the lock successfully.")
	}

	entry.SetValue(string(bytes))

	//Marhsal just the LockId into json and return it.
	j, err := json.Marshal(map[string]string{"lock_id": newid})
	if err != nil {
		logger.Errorf("Error unmarshaling JSON for key: %s: %s", key, err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
	logger.Infof("Handled successful request for: %s", key)
}