OXYGENHUB
# 3f3508bd5f16 oxygenhub-android / app / src / test / java / io / oxygenhub / android / api / HubClientTest.kt
5.5 KiB · last changed The hub's API and device sign-in, the token in the Keystore (refs #2) 11 days ago source blame history raw
1
package io.oxygenhub.android.api
2
3
import io.oxygenhub.android.Fixtures
4
import kotlinx.coroutines.test.runTest
5
import okhttp3.OkHttpClient
6
import okhttp3.mockwebserver.MockResponse
7
import okhttp3.mockwebserver.MockWebServer
8
import okhttp3.mockwebserver.SocketPolicy
9
import org.junit.After
10
import org.junit.Assert.assertEquals
11
import org.junit.Assert.assertFalse
12
import org.junit.Assert.assertTrue
13
import org.junit.Assert.fail
14
import org.junit.Before
15
import org.junit.Test
16
17
class HubClientTest {
18
    private lateinit var server: MockWebServer
19
    private val http = OkHttpClient()
20
    private var unauthorized = 0
21
22
    @Before
23
    fun setUp() {
24
        server = MockWebServer()
25
        server.start()
26
        unauthorized = 0
27
    }
28
29
    @After
30
    fun tearDown() {
31
        server.shutdown()
32
    }
33
34
    // MockWebServer speaks plain HTTP; the client takes any base it is given.
35
    private fun client() = HubClient(server.url("/").toString().trimEnd('/'), "oxy_secret", http) { unauthorized++ }
36
37
    private fun json(name: String, code: Int = 200) =
38
        MockResponse().setResponseCode(code).setHeader("Content-Type", "application/json").setBody(Fixtures.text(name))
39
40
    @Test
41
    fun userSendsTheBearerToken() = runTest {
42
        server.enqueue(json("user.json"))
43
        val u = client().user()
44
        assertEquals("andymccall", u.username)
45
        val req = server.takeRequest()
46
        assertEquals("GET", req.method)
47
        assertEquals("/api/v1/user", req.path)
48
        assertEquals("Bearer oxy_secret", req.getHeader("Authorization"))
49
        assertEquals("application/json", req.getHeader("Accept"))
50
    }
51
52
    @Test
53
    fun repositories() = runTest {
54
        server.enqueue(json("repos.json"))
55
        assertEquals(3, client().repositories().size)
56
        assertEquals("/api/v1/repos", server.takeRequest().path)
57
    }
58
59
    @Test
60
    fun issuesAskForTheState() = runTest {
61
        server.enqueue(json("issues.json"))
62
        val issues = client().issues("andymccall", "oxygenhub-android", IssueState.All)
63
        assertEquals(3, issues.size)
64
        assertEquals("/api/v1/repos/andymccall/oxygenhub-android/issues?state=all", server.takeRequest().path)
65
    }
66
67
    @Test
68
    fun pathSegmentsAreEncoded() = runTest {
69
        server.enqueue(MockResponse().setBody("[]"))
70
        client().issues("a b", "c/d")
71
        assertEquals("/api/v1/repos/a%20b/c%2Fd/issues?state=open", server.takeRequest().path)
72
    }
73
74
    @Test
75
    fun inboxWithALimit() = runTest {
76
        server.enqueue(json("inbox.json"))
77
        assertEquals(2, client().inbox(500).unread)
78
        assertEquals("/api/v1/notifications?limit=200", server.takeRequest().path)
79
    }
80
81
    @Test
82
    fun markingRead() = runTest {
83
        server.enqueue(MockResponse().setResponseCode(204))
84
        server.enqueue(MockResponse().setResponseCode(204))
85
        client().markRead(41)
86
        client().markAllRead()
87
        val one = server.takeRequest()
88
        assertEquals("POST", one.method)
89
        assertEquals("/api/v1/notifications/41/read", one.path)
90
        val all = server.takeRequest()
91
        assertEquals("POST", all.method)
92
        assertEquals("/api/v1/notifications/read", all.path)
93
    }
94
95
    @Test
96
    fun revokingDeletesTheOwnToken() = runTest {
97
        server.enqueue(MockResponse().setResponseCode(204))
98
        client().revokeToken()
99
        val req = server.takeRequest()
100
        assertEquals("DELETE", req.method)
101
        assertEquals("/api/v1/user/token", req.path)
102
        assertEquals("Bearer oxy_secret", req.getHeader("Authorization"))
103
    }
104
105
    @Test
106
    fun aProblemBecomesAnHttpError() = runTest {
107
        server.enqueue(json("problem_403.json", 403).setHeader("Content-Type", "application/problem+json"))
108
        try {
109
            client().user()
110
            fail("expected an error")
111
        } catch (e: HubException.Http) {
112
            assertEquals(403, e.status)
113
            assertEquals("this token lacks the user:read scope", e.detail)
114
            assertEquals("Not allowed: this token lacks the user:read scope", e.userMessage())
115
        }
116
        assertEquals(0, unauthorized)
117
    }
118
119
    @Test
120
    fun aRefusedTokenEndsTheSession() = runTest {
121
        server.enqueue(json("problem_401.json", 401))
122
        try {
123
            client().repositories()
124
            fail("expected an error")
125
        } catch (e: HubException.Http) {
126
            assertEquals(401, e.status)
127
        }
128
        assertEquals(1, unauthorized)
129
    }
130
131
    @Test
132
    fun revokingARefusedTokenDoesNotCallBack() = runTest {
133
        server.enqueue(json("problem_401.json", 401))
134
        try {
135
            client().revokeToken()
136
            fail("expected an error")
137
        } catch (e: HubException.Http) {
138
            assertEquals(401, e.status)
139
        }
140
        assertEquals(0, unauthorized)
141
    }
142
143
    @Test
144
    fun anUnreadableAnswer() = runTest {
145
        server.enqueue(MockResponse().setBody("<html>a proxy's page</html>"))
146
        try {
147
            client().repositories()
148
            fail("expected an error")
149
        } catch (e: HubException.Unreadable) {
150
            assertTrue(e.message!!.contains("/api/v1/repos"))
151
        }
152
    }
153
154
    @Test
155
    fun aBrokenConnection() = runTest {
156
        server.enqueue(MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AT_START))
157
        try {
158
            client().user()
159
            fail("expected an error")
160
        } catch (e: HubException.Network) {
161
            assertEquals("Can't reach the hub. Check your connection and try again.", e.userMessage())
162
        }
163
    }
164
165
    @Test
166
    fun theTokenIsNotInToString() {
167
        assertFalse(client().toString().contains("oxy_secret"))
168
    }
169
}