Replace HTTP status codes with IRC numeric replies in command handlers (closes #54)
All checks were successful
check / check (push) Successful in 2m17s
All checks were successful
check / check (push) Successful in 2m17s
IRC command handlers now return proper IRC numeric reply codes per
RFC 1459/2812 instead of HTTP status codes:
- 401 ERR_NOSUCHNICK for unknown DM targets
- 403 ERR_NOSUCHCHANNEL for invalid/missing channels
- 411 ERR_NORECIPIENT for missing message recipients
- 412 ERR_NOTEXTTOSEND for missing message body
- 421 ERR_UNKNOWNCOMMAND for unknown/empty commands
- 431 ERR_NONICKNAMEGIVEN for missing nick in NICK command
- 432 ERR_ERRONEUSNICKNAME for invalid nick format
- 433 ERR_NICKNAMEINUSE for taken nicks
- 442 ERR_NOTONCHANNEL for non-member channel actions
- 461 ERR_NEEDMOREPARAMS for missing required parameters
Error responses use the IRC numeric format:
{"command":"4xx","from":"server","to":"nick","body":["..."],"params":[...]}
HTTP status codes are now reserved for transport-level concerns:
- 400 for malformed HTTP requests (bad JSON)
- 401 for authentication failures
- 500 for internal server errors
Successful message sends changed from 201 to 200 since HTTP
status codes should not encode IRC-level semantics.
This commit is contained in:
@@ -668,11 +668,18 @@ func TestJoinMissingTo(t *testing.T) {
|
||||
tserver := newTestServer(t)
|
||||
token := tserver.createSession("joiner3")
|
||||
|
||||
status, _ := tserver.sendCommand(
|
||||
status, result := tserver.sendCommand(
|
||||
token, map[string]any{commandKey: joinCmd},
|
||||
)
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "461" {
|
||||
t.Fatalf(
|
||||
"expected IRC 461, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,9 +706,9 @@ func TestChannelMessage(t *testing.T) {
|
||||
bodyKey: []string{"hello world"},
|
||||
},
|
||||
)
|
||||
if status != http.StatusCreated {
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf(
|
||||
"expected 201, got %d: %v", status, result,
|
||||
"expected 200, got %d: %v", status, result,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -728,11 +735,18 @@ func TestMessageMissingBody(t *testing.T) {
|
||||
commandKey: joinCmd, toKey: "#test",
|
||||
})
|
||||
|
||||
status, _ := tserver.sendCommand(token, map[string]any{
|
||||
status, result := tserver.sendCommand(token, map[string]any{
|
||||
commandKey: privmsgCmd, toKey: "#test",
|
||||
})
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "412" {
|
||||
t.Fatalf(
|
||||
"expected IRC 412, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,12 +754,19 @@ func TestMessageMissingTo(t *testing.T) {
|
||||
tserver := newTestServer(t)
|
||||
token := tserver.createSession("noto")
|
||||
|
||||
status, _ := tserver.sendCommand(token, map[string]any{
|
||||
status, result := tserver.sendCommand(token, map[string]any{
|
||||
commandKey: privmsgCmd,
|
||||
bodyKey: []string{"hello"},
|
||||
})
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "411" {
|
||||
t.Fatalf(
|
||||
"expected IRC 411, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -760,7 +781,7 @@ func TestNonMemberCannotSend(t *testing.T) {
|
||||
})
|
||||
|
||||
// Alice tries to send without joining.
|
||||
status, _ := tserver.sendCommand(
|
||||
status, result := tserver.sendCommand(
|
||||
aliceToken,
|
||||
map[string]any{
|
||||
commandKey: privmsgCmd,
|
||||
@@ -768,8 +789,15 @@ func TestNonMemberCannotSend(t *testing.T) {
|
||||
bodyKey: []string{"sneaky"},
|
||||
},
|
||||
)
|
||||
if status != http.StatusForbidden {
|
||||
t.Fatalf("expected 403, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "442" {
|
||||
t.Fatalf(
|
||||
"expected IRC 442, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,9 +814,9 @@ func TestDirectMessage(t *testing.T) {
|
||||
bodyKey: []string{"hey bob"},
|
||||
},
|
||||
)
|
||||
if status != http.StatusCreated {
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf(
|
||||
"expected 201, got %d: %v", status, result,
|
||||
"expected 200, got %d: %v", status, result,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -818,13 +846,20 @@ func TestDMToNonexistentUser(t *testing.T) {
|
||||
tserver := newTestServer(t)
|
||||
token := tserver.createSession("dmsender")
|
||||
|
||||
status, _ := tserver.sendCommand(token, map[string]any{
|
||||
status, result := tserver.sendCommand(token, map[string]any{
|
||||
commandKey: privmsgCmd,
|
||||
toKey: "nobody",
|
||||
bodyKey: []string{"hello?"},
|
||||
})
|
||||
if status != http.StatusNotFound {
|
||||
t.Fatalf("expected 404, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "401" {
|
||||
t.Fatalf(
|
||||
"expected IRC 401, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -871,12 +906,19 @@ func TestNickCollision(t *testing.T) {
|
||||
|
||||
tserver.createSession("taken_nick")
|
||||
|
||||
status, _ := tserver.sendCommand(token, map[string]any{
|
||||
status, result := tserver.sendCommand(token, map[string]any{
|
||||
commandKey: "NICK",
|
||||
bodyKey: []string{"taken_nick"},
|
||||
})
|
||||
if status != http.StatusConflict {
|
||||
t.Fatalf("expected 409, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "433" {
|
||||
t.Fatalf(
|
||||
"expected IRC 433, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -884,12 +926,19 @@ func TestNickInvalid(t *testing.T) {
|
||||
tserver := newTestServer(t)
|
||||
token := tserver.createSession("nickval")
|
||||
|
||||
status, _ := tserver.sendCommand(token, map[string]any{
|
||||
status, result := tserver.sendCommand(token, map[string]any{
|
||||
commandKey: "NICK",
|
||||
bodyKey: []string{"bad nick!"},
|
||||
})
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "432" {
|
||||
t.Fatalf(
|
||||
"expected IRC 432, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -897,11 +946,18 @@ func TestNickEmptyBody(t *testing.T) {
|
||||
tserver := newTestServer(t)
|
||||
token := tserver.createSession("nicknobody")
|
||||
|
||||
status, _ := tserver.sendCommand(
|
||||
status, result := tserver.sendCommand(
|
||||
token, map[string]any{commandKey: "NICK"},
|
||||
)
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "431" {
|
||||
t.Fatalf(
|
||||
"expected IRC 431, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,12 +994,19 @@ func TestTopicMissingTo(t *testing.T) {
|
||||
tserver := newTestServer(t)
|
||||
token := tserver.createSession("topicnoto")
|
||||
|
||||
status, _ := tserver.sendCommand(token, map[string]any{
|
||||
status, result := tserver.sendCommand(token, map[string]any{
|
||||
commandKey: "TOPIC",
|
||||
bodyKey: []string{"topic"},
|
||||
})
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "461" {
|
||||
t.Fatalf(
|
||||
"expected IRC 461, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -955,11 +1018,18 @@ func TestTopicMissingBody(t *testing.T) {
|
||||
commandKey: joinCmd, toKey: "#topictest",
|
||||
})
|
||||
|
||||
status, _ := tserver.sendCommand(token, map[string]any{
|
||||
status, result := tserver.sendCommand(token, map[string]any{
|
||||
commandKey: "TOPIC", toKey: "#topictest",
|
||||
})
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "461" {
|
||||
t.Fatalf(
|
||||
"expected IRC 461, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1027,11 +1097,18 @@ func TestUnknownCommand(t *testing.T) {
|
||||
tserver := newTestServer(t)
|
||||
token := tserver.createSession("cmdtest")
|
||||
|
||||
status, _ := tserver.sendCommand(
|
||||
status, result := tserver.sendCommand(
|
||||
token, map[string]any{commandKey: "BOGUS"},
|
||||
)
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "421" {
|
||||
t.Fatalf(
|
||||
"expected IRC 421, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1039,11 +1116,18 @@ func TestEmptyCommand(t *testing.T) {
|
||||
tserver := newTestServer(t)
|
||||
token := tserver.createSession("emptycmd")
|
||||
|
||||
status, _ := tserver.sendCommand(
|
||||
status, result := tserver.sendCommand(
|
||||
token, map[string]any{commandKey: ""},
|
||||
)
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", status)
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", status)
|
||||
}
|
||||
|
||||
if result[commandKey] != "421" {
|
||||
t.Fatalf(
|
||||
"expected IRC 421, got %v",
|
||||
result[commandKey],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user