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