Skip to main content
  1. Posts/

Day 55 - Two more

OldDays seitan-spin cucumber csharp ruby
Table of Contents

Two more tests!
Two more tests!

An easy one
#

features/connect.feature
12
13
14
15
16
Scenario: Allow connection if server in Running mode
Given I use the "minimal" database as-is
When the server executable is started
And I allow time for the server to complete startup
Then I can connect to the server via telnet

This one’s pretty trivial; we just implement the opposite steps to the ones we did for “Disallow connection if server in Starting mode”. In truth, it’s somewhat redundant; if this didn’t work, none of the login tests would work, but we’ll leave it here for completeness.

7 scenarios (7 passed)
33 steps (33 passed)
2m14.275s

useradd
#

features/connect.feature
19
20
21
22
23
24
25
26
27
Scenario: Allow connection if server in Locked mode
Given I use the "minimal" database as-is
When the server executable is started
And I allow time for the server to complete startup
When I log on using a developer account
And I enter the chat
And I issue the "/lockserver" command
And I disconnect from the server
Then I can connect to the server via telnet

To get the server in Locked mode, we need to have an admin log in and lock it. Let’s see what allows a user to use /lockserver

DragonsSpine/Menus/Conference.cs
1669
1670
1671
1672
1673
1674
1675
1676
case "/lockserver":
  if (ch.ImpLevel >= Globals.eImpLevel.DEV)
  {
    DragonsSpineMain.ServerStatus = DragonsSpineMain.ServerState.Locked;
    ch.WriteLine("Game world has been locked.", Protocol.TextType.System);
  }
  else { SendInvalidCommand(ch); }
  break;

impLevel is in the Player table, so we need to make sure we have an Account and a Player. We start with an ugly-but-it-works solution, but then split it up into reasonable methods:

features/steps/login_steps.rb
164
165
166
167
168
169
170
171
When(/^I log on using a developer account$/) do
  @user = { acct_name: "dev01", acct_password: "devpass01" }
  ensure_developer_account_exists(@user[:acct_name], @user[:acct_password])
  @connection = create_telnet_connection
  telnet_command(@connection, "", /Login\: /, {"Timeout" => 120})
  telnet_commands(@connection, [[@user[:acct_name], /Password\: /],
                [@user[:acct_password], /Command\: /]])
end
features/lib/db_helper.rb
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def ensure_developer_account_exists(acct_name, acct_password)
  accountID = find_or_create_account(acct_name, acct_password)
  # now that we have an accountID we can make the player
  client = connect_to_db(@server_database)
  # first delete any players already attached to this accountID
  query = "DELETE \
  FROM [#{@server_database}].[dbo].[Player]
  WHERE [accountID] = #{accountID}"
  result = client.execute(query)
  affected_rows = result.do
  puts "Pre-existing players for account ID #{accountID} deleted: #{affected_rows}"  
  # now insert the new player with DEV access
  db_insert_player({accountID: accountID, account: acct_name, impLevel: 4})
end
features/lib/db_helper.rb
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
def find_or_create_account(acct_name, acct_password)
  client = connect_to_db(@server_database)
  # Nothing prevents identical users, so we need to check if it's already there:
  accountID = nil
  result = client.execute("SELECT * FROM [#{@server_database}].[dbo].[Account] \
              WHERE [account] = '#{acct_name}'") 
  result.each do |row|
  accountID = row['accountID']
  end
  fail "duplicate users!" if result.affected_rows > 1
  if nil == accountID
  query =  "INSERT INTO [#{@server_database}].[dbo].[Account] \
    ([account],[password],[email]) VALUES \
    ('#{acct_name}', '#{acct_password}', '#{acct_name}@test.not')"
  puts query
  result = client.execute(query)
  affected_rows = result.do
  puts affected_rows
  fail "Failed to insert user!" if 1 != affected_rows  
  end
  result = client.execute("SELECT * FROM [#{@server_database}].[dbo].[Account] \
              WHERE [account] = '#{acct_name}'") 
  result.each do |row|
  puts row
  accountID = row['accountID']
  end
  fail "duplicate users!" if result.affected_rows > 1
  accountID
end
features/lib/db/player.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Plan to build this out over time as necessary
DEFAULT_PLAYER = {
  accountID: 0,
  account: 'no_name',
  name: 'no_name',
  impLevel: 0
}

def db_insert_player(db_hash)
  # anything in the hash overrides defaults
  player = DEFAULT_PLAYER.merge(db_hash)
  client = connect_to_db(@server_database)
  query = "INSERT INTO [#{@server_database}].[dbo].[Player] ([notes], [accountID], [account], \
  [name], [gender], [race], [classFullName], [classType], [visualKey], [alignment], [confRoom], \
  [impLevel], \
  [ancestor], [ancestorID], [facet], [land], [map], [xCord], [yCord], [zCord], [dirPointer], \
  [stunned], [floating], [dead], [fighterSpecialization], [level], [exp], [hits], [hitsMax], \
  [hitsAdjustment], [hitsDoctored], [stamina], [stamLeft], [staminaAdjustment], [mana], \
  [manaMax], [manaAdjustment], [age], [roundsPlayed], [numKills], [numDeaths], [bankGold], \
  [strength], [dexterity], [intelligence], [wisdom], [constitution], [charisma], [strengthAdd], \
  [dexterityAdd], [birthday], [lastOnline], [deleteDate], [currentKarma], [lifetimeKarma], \
  [lifetimeMarks], [pvpKills], [pvpDeaths], [playersKilled], [playersFlagged], [UW_hitsMax], \
  [UW_hitsAdjustment], [UW_staminaMax], [UW_staminaAdjustment], [UW_manaMax], \
  [UW_manaAdjustment], [UW_intestines], [UW_liver], [UW_lungs], [UW_stomach]) \
  VALUES (N'', #{player[:accountID]}, \
  N'#{player[:account]}', \
  N'#{player[:name]}', \
  1, N'Illyria', N'Fighter', \
  N'Fighter', N'male_fighter_pc_brown', 1, 0, #{player[:impLevel]}, 0, 0, 0, 0, 0, 42, 27, 0, \
  N'v', 0, 3, 0, N'None', 4, 4996, 36, 36, 0, 0, 10, 10, 0, 0, 0, 0, 806, 806, 8, \
  0, 0, 17, 18, 10, 17, 8, 18, 1, 1, CAST(0x0000A4FC0001D163 AS DateTime), \
  CAST(0x0000A4FC001A5F6A AS DateTime), CAST(0x0000979200000000 AS DateTime), \
  0, 0, 0, 0, 0, N'', N'', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)"
  result = client.execute(query)
  affected_rows = result.do
  fail "Unable to insert player!" if 1 != affected_rows
end

After this, the steps for getting into the chat and issuing the lock command are pretty trivial.

8 scenarios (8 passed)
42 steps (42 passed)
2m5.928s

Slow going
#

Making such slow progress, it seems like I’ll never get a decent set of tests up and running. But we’re building up an inventory of reusable code that will make future tests easier to implement.

The big question is: How do we approach such a big test project, really, and how do we organize the work? I’ve been considering that, and think I have an approach to try. Tomorrow.


More to come
More to come

Day 55 code - tests