GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

Commit fa6c8fc4 authored by Philipp Winter's avatar Philipp Winter

Merge branch 'issue/6' into 'master'

Issue/6

Closes #6

See merge request !2
parents 37d7978e b75e6e1b
...@@ -55,7 +55,8 @@ The service responds with the following JSON: ...@@ -55,7 +55,8 @@ The service responds with the following JSON:
{ {
"bridge_results": { "bridge_results": {
"BRIDGE_LINE_1": { "BRIDGE_LINE_1": {
"functional: BOOL, "functional": BOOL,
"last_tested": "STRING",
"error": "STRING", (only present if "functional" is false) "error": "STRING", (only present if "functional" is false)
}, },
... ...
...@@ -68,10 +69,12 @@ The service responds with the following JSON: ...@@ -68,10 +69,12 @@ The service responds with the following JSON:
} }
In a nutshell, the "bridge_results" dictionary maps bridge lines (as they were In a nutshell, the "bridge_results" dictionary maps bridge lines (as they were
provided in the request) to a dictionary consisting of two keys: "functional" provided in the request) to a dictionary consisting of three keys: "functional"
is set to "true" if tor could fetch the bridge's descriptor. If tor was unable is set to "true" if tor could fetch the bridge's descriptor. If tor was unable
to fetch the bridge's descriptor, "functional" is set to "false" and the to fetch the bridge's descriptor, "functional" is set to "false" and the
"error" key maps to an error string. "error" key maps to an error string. The key "last_tested" maps to a string
representation (in ISO 8601 format) of the UTC time and date the bridge was
last tested.
In addition to the "bridge_results" dictionary, the response may contain an In addition to the "bridge_results" dictionary, the response may contain an
optional "error" key if the entire test failed (e.g. if bridgestrap failed to optional "error" key if the entire test failed (e.g. if bridgestrap failed to
...@@ -90,10 +93,12 @@ Here are a few examples: ...@@ -90,10 +93,12 @@ Here are a few examples:
{ {
"bridge_results": { "bridge_results": {
"obfs4 1.2.3.4:1234 cert=fJRlJc0T7i2Qkw3SyLQq+M6iTGs9ghLHK65LBy/MQewXJpNOKFq63Om1JHVkLlrmEBbX1w iat-mode=0": { "obfs4 1.2.3.4:1234 cert=fJRlJc0T7i2Qkw3SyLQq+M6iTGs9ghLHK65LBy/MQewXJpNOKFq63Om1JHVkLlrmEBbX1w iat-mode=0": {
"functional": true "functional": true,
"last_tested": "2020-11-12T19:42:16.736853122Z"
}, },
"1.2.3.4:1234": { "1.2.3.4:1234": {
"functional": false, "functional": false,
"last_tested": "2020-11-10T09:44:45.877531581Z",
"error": "timed out waiting for bridge descriptor" "error": "timed out waiting for bridge descriptor"
} }
}, },
...@@ -104,6 +109,7 @@ Here are a few examples: ...@@ -104,6 +109,7 @@ Here are a few examples:
"bridge_results": { "bridge_results": {
"1.2.3.4:1234 1234567890ABCDEF1234567890ABCDEF12345678": { "1.2.3.4:1234 1234567890ABCDEF1234567890ABCDEF12345678": {
"functional": false, "functional": false,
"last_tested": "2020-11-10T09:44:45.877531581Z",
"error": "timed out waiting for bridge descriptor" "error": "timed out waiting for bridge descriptor"
} }
}, },
......
...@@ -117,8 +117,9 @@ func (tc *TestCache) IsCached(bridgeLine string) *CacheEntry { ...@@ -117,8 +117,9 @@ func (tc *TestCache) IsCached(bridgeLine string) *CacheEntry {
return r return r
} }
// AddEntry adds an entry for the given bridge and test result to our cache. // AddEntry adds an entry for the given bridge, test result, and test time to
func (tc *TestCache) AddEntry(bridgeLine string, result error) { // our cache.
func (tc *TestCache) AddEntry(bridgeLine string, result error, lastTested time.Time) {
addrPort, err := bridgeLineToAddrPort(bridgeLine) addrPort, err := bridgeLineToAddrPort(bridgeLine)
if err != nil { if err != nil {
...@@ -132,6 +133,6 @@ func (tc *TestCache) AddEntry(bridgeLine string, result error) { ...@@ -132,6 +133,6 @@ func (tc *TestCache) AddEntry(bridgeLine string, result error) {
errorStr = result.Error() errorStr = result.Error()
} }
cacheMutex.Lock() cacheMutex.Lock()
(*tc)[addrPort] = &CacheEntry{errorStr, time.Now()} (*tc)[addrPort] = &CacheEntry{errorStr, lastTested}
cacheMutex.Unlock() cacheMutex.Unlock()
} }
...@@ -21,14 +21,14 @@ func TestCacheFunctions(t *testing.T) { ...@@ -21,14 +21,14 @@ func TestCacheFunctions(t *testing.T) {
t.Errorf("Cache is empty but marks bridge line as existing.") t.Errorf("Cache is empty but marks bridge line as existing.")
} }
cache.AddEntry(bridgeLine, nil) cache.AddEntry(bridgeLine, nil, time.Now().UTC())
e = cache.IsCached(bridgeLine) e = cache.IsCached(bridgeLine)
if e == nil { if e == nil {
t.Errorf("Could not retrieve existing element from cache.") t.Errorf("Could not retrieve existing element from cache.")
} }
testError := fmt.Errorf("bridge is on fire") testError := fmt.Errorf("bridge is on fire")
cache.AddEntry(bridgeLine, testError) cache.AddEntry(bridgeLine, testError, time.Now().UTC())
e = cache.IsCached(bridgeLine) e = cache.IsCached(bridgeLine)
if e.Error != testError.Error() { if e.Error != testError.Error() {
t.Errorf("Got test result %q but expected %q.", e.Error, testError) t.Errorf("Got test result %q but expected %q.", e.Error, testError)
...@@ -45,7 +45,7 @@ func TestCacheExpiration(t *testing.T) { ...@@ -45,7 +45,7 @@ func TestCacheExpiration(t *testing.T) {
cache[bridgeLine1] = &CacheEntry{"", expiry} cache[bridgeLine1] = &CacheEntry{"", expiry}
bridgeLine2 := "2.2.2.2:2222" bridgeLine2 := "2.2.2.2:2222"
cache[bridgeLine2] = &CacheEntry{"", time.Now()} cache[bridgeLine2] = &CacheEntry{"", time.Now().UTC()}
e := cache.IsCached(bridgeLine1) e := cache.IsCached(bridgeLine1)
if e != nil { if e != nil {
...@@ -72,7 +72,7 @@ func BenchmarkIsCached(b *testing.B) { ...@@ -72,7 +72,7 @@ func BenchmarkIsCached(b *testing.B) {
numCacheEntries := 10000 numCacheEntries := 10000
cache := make(TestCache) cache := make(TestCache)
for i := 0; i < numCacheEntries; i++ { for i := 0; i < numCacheEntries; i++ {
cache.AddEntry(getRandAddrPort(), getRandError()) cache.AddEntry(getRandAddrPort(), getRandError(), time.Now().UTC())
} }
// How long does it take to iterate over numCacheEntries cache entries? // How long does it take to iterate over numCacheEntries cache entries?
...@@ -86,8 +86,8 @@ func TestCacheSerialisation(t *testing.T) { ...@@ -86,8 +86,8 @@ func TestCacheSerialisation(t *testing.T) {
cache := make(TestCache) cache := make(TestCache)
testError := fmt.Errorf("foo") testError := fmt.Errorf("foo")
cache.AddEntry("1.1.1.1:1", testError) cache.AddEntry("1.1.1.1:1", testError, time.Now().UTC())
cache.AddEntry("2.2.2.2:2", fmt.Errorf("bar")) cache.AddEntry("2.2.2.2:2", fmt.Errorf("bar"), time.Now().UTC())
tmpFh, err := ioutil.TempFile(os.TempDir(), "cache-file-") tmpFh, err := ioutil.TempFile(os.TempDir(), "cache-file-")
if err != nil { if err != nil {
...@@ -132,7 +132,7 @@ func TestCacheConcurrency(t *testing.T) { ...@@ -132,7 +132,7 @@ func TestCacheConcurrency(t *testing.T) {
byte((i>>16)&0xff), byte((i>>16)&0xff),
byte((i>>8)&0xff), byte((i>>8)&0xff),
byte(i&0xff)) byte(i&0xff))
cache.AddEntry(fmt.Sprintf("%s:1234", ipAddr.String()), nil) cache.AddEntry(fmt.Sprintf("%s:1234", ipAddr.String()), nil, time.Now().UTC())
} }
doneWriting <- true doneWriting <- true
}() }()
......
...@@ -20,8 +20,9 @@ var FailurePage string ...@@ -20,8 +20,9 @@ var FailurePage string
// BridgeTest represents the result of a bridge test, sent back to the client // BridgeTest represents the result of a bridge test, sent back to the client
// as JSON object. // as JSON object.
type BridgeTest struct { type BridgeTest struct {
Functional bool `json:"functional"` Functional bool `json:"functional"`
Error string `json:"error,omitempty"` LastTested time.Time `json:"last_tested"`
Error string `json:"error,omitempty"`
} }
// TestResult represents the result of a test. // TestResult represents the result of a test.
...@@ -98,8 +99,11 @@ func testBridgeLines(bridgeLines []string) *TestResult { ...@@ -98,8 +99,11 @@ func testBridgeLines(bridgeLines []string) *TestResult {
for _, bridgeLine := range bridgeLines { for _, bridgeLine := range bridgeLines {
if entry := cache.IsCached(bridgeLine); entry != nil { if entry := cache.IsCached(bridgeLine); entry != nil {
numCached++ numCached++
result.Bridges[bridgeLine] = &BridgeTest{Functional: entry.Error == "", result.Bridges[bridgeLine] = &BridgeTest{
Error: entry.Error} Functional: entry.Error == "",
LastTested: entry.Time,
Error: entry.Error,
}
} else { } else {
remainingBridgeLines = append(remainingBridgeLines, bridgeLine) remainingBridgeLines = append(remainingBridgeLines, bridgeLine)
} }
...@@ -116,7 +120,7 @@ func testBridgeLines(bridgeLines []string) *TestResult { ...@@ -116,7 +120,7 @@ func testBridgeLines(bridgeLines []string) *TestResult {
// Cache partial test results and add them to our existing result object. // Cache partial test results and add them to our existing result object.
for bridgeLine, bridgeTest := range partialResult.Bridges { for bridgeLine, bridgeTest := range partialResult.Bridges {
cache.AddEntry(bridgeLine, errors.New(bridgeTest.Error)) cache.AddEntry(bridgeLine, errors.New(bridgeTest.Error), bridgeTest.LastTested)
result.Bridges[bridgeLine] = bridgeTest result.Bridges[bridgeLine] = bridgeTest
} }
} else { } else {
......
...@@ -236,10 +236,17 @@ func (c *TorContext) TestBridgeLines(bridgeLines []string) *TestResult { ...@@ -236,10 +236,17 @@ func (c *TorContext) TestBridgeLines(bridgeLines []string) *TestResult {
parser.Feed(line) parser.Feed(line)
if parser.State == BridgeStateSuccess { if parser.State == BridgeStateSuccess {
log.Printf("Setting %s to 'true'", bridgeLine) log.Printf("Setting %s to 'true'", bridgeLine)
result.Bridges[bridgeLine] = &BridgeTest{Functional: true} result.Bridges[bridgeLine] = &BridgeTest{
Functional: true,
LastTested: time.Now().UTC(),
}
} else if parser.State == BridgeStateFailure { } else if parser.State == BridgeStateFailure {
log.Printf("Setting %s to 'false'", bridgeLine) log.Printf("Setting %s to 'false'", bridgeLine)
result.Bridges[bridgeLine] = &BridgeTest{Functional: false, Error: parser.Reason} result.Bridges[bridgeLine] = &BridgeTest{
Functional: false,
Error: parser.Reason,
LastTested: time.Now().UTC(),
}
} }
} }
...@@ -254,8 +261,11 @@ func (c *TorContext) TestBridgeLines(bridgeLines []string) *TestResult { ...@@ -254,8 +261,11 @@ func (c *TorContext) TestBridgeLines(bridgeLines []string) *TestResult {
// Mark whatever bridge results we're missing as nonfunctional. // Mark whatever bridge results we're missing as nonfunctional.
for _, bridgeLine := range bridgeLines { for _, bridgeLine := range bridgeLines {
if _, exists := result.Bridges[bridgeLine]; !exists { if _, exists := result.Bridges[bridgeLine]; !exists {
result.Bridges[bridgeLine] = &BridgeTest{Functional: false, result.Bridges[bridgeLine] = &BridgeTest{
Error: "timed out waiting for bridge descriptor"} Functional: false,
Error: "timed out waiting for bridge descriptor",
LastTested: time.Now().UTC(),
}
} }
} }
return result return result
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment