Docstoc

DATA FORMATTING

Document Sample
DATA FORMATTING Powered By Docstoc
					     AUTOMATING SS7 STP INTEROPERABILITY TEST RESULTS
                                 ANALYSIS

                                   THESIS

                        Submitted in Partial Fulfillment
                          of the Requirements for the
                                   Degree of
                 MASTER OF SCIENCE (Electrical Engineering)


                                     at the


                        POLYTECHNIC UNIVERSITY
                                      by


                                Ramesh Badri


                                 October 2001
                                                    Approved:
                  __________________________        __________________________
                                  Co-Advisor                            Advisor
                  __________________________        __________________________
                                        Date                               Date
                                                    __________________________
                                                                Department Head
                                                    __________________________
                                                                           Date
Copy No. _____
                                                                               ii



                                      Vita


January 25, 1978 ……………………………….. Born – Hyderabad, India
July, 1995 - June, 1999 ………………………… B. Tech. Electrical Engg., Indian
                                      Institute of Technology, Madras, India
August, 1999 – October, 2001 …………………. M. S. Electrical Engineering,
                                      Polytechnic University, Brooklyn, NY
                                                                                                 iii




                                       Acknowledgments

I would like to thank my advisor Dr. Malathi Veeraraghavan for giving me an opportunity to
work on this project. I also thank her for all that I learnt from her in the past two years. I
would also like to thank my co-advisor Dr. Tim Moors for all the time he spent discussing
and improving this work. I would also like to record my sincere thanks to the other members
of the project team, Jeff Tao, Xuan Zheng, and Tao Li. The project was made possible by a
CATT (Center for Advanced Technology in Telecommunication) research contract funded
by Verizon Communications. Many documents that were used to develop the thesis were
provided by Verizon. However, these being proprietary, they are not explicitly referenced in
the thesis. I would finally like to thank Verizon Communications for allowing us to use their
Systems Integration and Testing lab at Silver Spring to gather data to test our software.
                                                                                                 iv


                                        AN ABSTRACT
      AUTOMATING SS7 STP INTEROPERABILITY TEST RESULTS ANALYSIS
                                                by
                                          Ramesh Badri
                                Advisor: Malathi Veeraraghavan
                                    Co-Advisor: Tim Moors
  Submitted in Partial Fulfillment of the Requirements for the Degree of Master of Science
                                     (Electrical Engineering)
                                          October 2001


The Public Switched Telephone Network (PSTN) uses a protocol standard called Signaling
System Number 7 (SS7) for signaling and to provide features like 800 number calls, credit
card authentication, caller I.D., wireless roaming services etc. SS7 is a packet switched
network and the datagram switches in SS7 networks are called Signaling Transfer Points
(STPs). STPs are maunfactured by a number of vendors, each issuing a new software release
almost every year. Before a new STP is deployed, it has to be tested to verify that it can
function correctly as a part of the network consisting of other STPs. This testing is termed
STP interoperability testing and is usually performed manually. Manual testing leads to a
slow deployment of the STPs in the field and prevents the service provider from offering
services based on the new features quickly. Manual testing is also cumbersome and error-
prone. Testing consists of four phases: setting up the test configuration, executing the test
steps, retrieving the test results and analyzing the test results. This thesis considers the task of
automating the analysis of STP interoperability test results. We develop an analysis
methodology suitable to be automated and implement this methodology in software. The
analysis involves comparing the actual behavior of the STPs in response to the tests with
their expected behavior as per the specifications. The software is written in the programming
language Perl and is called ASTRA (Automated SS7 Test Result Analyzer). ASTRA was
used to analyze the results of a few STP tests that were conducted by our industry sponsor.
The time required to analyze the test results was reduced to a few minutes from several hours
typically needed for manual analysis. The correctness of the analysis was also greatly
improved.
                                                                                                                                         v


                                                       Table of Contents
Acknowledgments.................................................................................................................... iii
List of Figures………………………………………………………………………………..vii
List of Tables.……………………………………………………………………………….viii
1    Introduction ....................................................................................................................... 1
2    Background ....................................................................................................................... 3
  2.1      SS7 Overview ........................................................................................................... 3
     2.1.1     SS7 Network Elements ..................................................................................... 3
     2.1.2     SS7 Signaling Links .......................................................................................... 4
     2.1.3     Basic SS7 Network Architecture ...................................................................... 5
     2.1.4     SS7 Protocol Stack............................................................................................ 6
     2.1.5     A brief review of MTP Level 3 network management ..................................... 8
     2.1.6     Comparison with IP .......................................................................................... 9
  2.2      SS7 Interoperability Testing ................................................................................... 11
  2.3      The Testing Procedure ............................................................................................ 12
     2.3.1     Set up .............................................................................................................. 12
     2.3.2     Execution ........................................................................................................ 13
     2.3.3     Data Retrieval ................................................................................................. 13
     2.3.4     Analysis........................................................................................................... 13
  2.4      Need for Automation .............................................................................................. 13
3    Overview of the Analysis Methodology and Software Architecture .............................. 15
  3.1      Analysis Methodology ............................................................................................ 15
     3.1.1     Introduction ..................................................................................................... 15
     3.1.2     Analysis methodology .................................................................................... 16
  3.2      Overview of Automated SS7 Test Results Analyzer (ASTRA) ............................. 18
     3.2.1     Naming scheme for configuration components .............................................. 20
     3.2.2     Inputs to the software ...................................................................................... 21
     3.2.3     Choice of the programming Language ........................................................... 26
4    Expressing the Expected Behavior for Automation........................................................ 28
  4.1      Expected Behavior Format ..................................................................................... 29
     4.1.1     Identifiers ........................................................................................................ 29
     4.1.2     Timing relationships between events .............................................................. 31
     4.1.3     Control mechanisms........................................................................................ 32
     4.1.4     Test Action events........................................................................................... 34
     4.1.5     Expected behavior ........................................................................................... 34
  4.2      Example of Expected Behavior for a test ............................................................... 36
5    Data Formatting .............................................................................................................. 38
  5.1      Description .............................................................................................................. 38
     5.1.1     Filtering ........................................................................................................... 38
     5.1.2     Abstraction to form Generic Events ............................................................... 38
     5.1.3     Establishing consistency ................................................................................. 38
     5.1.4     Integration of event records ............................................................................ 39
     5.1.5     Preparing for analysis ..................................................................................... 39
  5.2      Implementation ....................................................................................................... 39
  5.3      Usage....................................................................................................................... 43
     5.3.1     Requirements .................................................................................................. 43
                                                                                                                                         vi


     5.3.2       Command Usage ............................................................................................. 43
     5.3.3       Inputs............................................................................................................... 43
     5.3.4       Output produced.............................................................................................. 44
6    The Matching Process ..................................................................................................... 47
  6.1      The Translator ......................................................................................................... 47
     6.1.1       Introduction ..................................................................................................... 47
     6.1.2       Operation and Implementation ....................................................................... 48
     6.1.3       Usage............................................................................................................... 63
  6.2      Specific Analyzer .................................................................................................... 64
     6.2.1       Requirements .................................................................................................. 64
     6.2.2       Usage............................................................................................................... 65
     6.2.3       Inputs............................................................................................................... 65
     6.2.4       Outputs produced ............................................................................................ 65
  6.3      Matching Library .................................................................................................... 73
     6.3.1       Requirements .................................................................................................. 73
     6.3.2       Interface with the Specific Analyzer............................................................... 73
     6.3.3       The matching procedure ................................................................................. 73
     6.3.4       The Functions.................................................................................................. 75
7    Event Summarizer........................................................................................................... 82
  7.1      Operation................................................................................................................. 82
     7.1.1       Produce the Unexpected Event List ................................................................ 82
     7.1.2       Calculate event statistics ................................................................................. 82
  7.2      Command Usage ..................................................................................................... 83
  7.3      Inputs....................................................................................................................... 83
  7.4      Outputs produced .................................................................................................... 84
     7.4.1       Unexpected Event List: ................................................................................... 84
     7.4.2       Event Numbers File ........................................................................................ 85
8    Report Generator ............................................................................................................. 88
  8.1      Implementation ....................................................................................................... 88
     8.1.1       Report event statistics ..................................................................................... 88
     8.1.2       Obtain and organize parameter observations .................................................. 88
     8.1.3       Write timer observations ................................................................................. 89
     8.1.4       Produce the detailed analysis table ................................................................. 90
  8.2      Usage and Inputs ..................................................................................................... 90
  8.3      Output Produced ..................................................................................................... 91
     8.3.1       Classification of test results ............................................................................ 91
     8.3.2       Color coding of test results ............................................................................. 91
     8.3.3       Overview level of reports................................................................................ 92
     8.3.4       Detailed analysis ............................................................................................. 97
9    Conclusion and future work .......................................................................................... 100
Appendix A: File naming scheme......................................................................................... 101
Appendix B: File structure format ........................................................................................ 102
Appendix C: Example Test Network Configuration ............................................................ 104
Appendix D: Allowable message types and parameters for findmsg() ................................ 105
Appendix E: ASTRA source code ........................................................................................ 105
References ............................................................................................................................. 161
                                                                                                                                           vii




                                                           List of Figures

Figure 2.1: SS7 network elements ............................................................................................ 3
Figure 2.2: Various types of SS7 links ..................................................................................... 4
Figure 2.3 Basic SS7 network ................................................................................................... 6
Figure 2.4 SS7 Protocol layers shown in relation with the OSI model and TCP/IP protocol
     stack .................................................................................................................................. 7
Figure 3.1 ASTRA software architecture ............................................................................... 19
Figure 3.2: Excerpt of a Test Action List. .............................................................................. 24
Figure 3.3: Excerpt of a Recorded Times of Test Actions file. .............................................. 25
Figure 5.1 Inputs and output of the data formatter ................................................................. 44
Figure 6.1 Relationship between Expected Behaviour, Translator and Specific Analyzer .... 47
Figure 6.2 Ordering of the Expected Behaviour tree by the Translator……………………..
Figure 6.3 Simple events and compound events
Figure 6.4 Depth first tree traversal and timing information
Figure 6.5 Expansion of the foreach loop
Figure 6.6 Expansion of the while loop
Figure 6.7 Inputs and output of the Translator
Figure 6.8 Inputs and output of the Specific Analyzer
Figure 6.9 The matching procedure
Figure 7.1 Procedure of producing the Unexpected Event List .............................................. 82
Figure 7.2 Inputs and outputs to the Event Summarizer ......................................................... 84
Figure 8.1 Inputs and output of the Report Generator ............................................................ 90
                                                                                                                         viii


                                                     List of Tables
Table 1 : Notation used in the analysis methodology ............................................................. 16
Table 2: Names of intermediate files and their file handle names .......................................... 51
Table 3: Description of colour codes ...................................................................................... 92
                                                                                                1


1 Introduction
Signaling System No. 7 (SS7) is a global standard for telecommunications defined by the
International Telecommunication Union (ITU) Telecommunication Standardization Sector
(ITU-T). The standard defines the procedures and protocol by which network elements in the
public switched telephone network (PSTN) exchange information over a digital signaling
network to effect wireless (cellular) and wire-line call setup, routing and control.
The SS7 network and protocol are used for:

      Basic call setup, management, and tear down
      Wireless services such as personal communications services (PCS), wireless roaming,
       and mobile subscriber authentication
      Local number portability (LNP)
      Toll-free (800/888) and toll (900) wire-line services
      Enhanced call features such as call forwarding, calling party name/number display,
       and three-way calling

   An important part of the SS7 networks are the Signaling Transfer Points (STPs), which
are produced by various vendors. Each new release of an STP needs to be tested to ensure
that it performs properly, and can interoperate with existing network components. This
testing is called interoperability testing. Interoperability testing needs to be repeated for each
new release of a STP (multiple times per year) and with STPs from different vendors. SS7
STP tests can benefit greatly from automation because they need to be repeated often, and are
labor intensive.

   There are four parts in the STP testing process: setting up of the test network
configuration, performing the test steps, retrieving the test results from the test elements and
analyzing the test results to determine whether the STP passed or failed the test.

    The goal of this thesis is to automate the analysis of SS7 STP interoperability test
results. Chapter 2 provides the necessary background regarding SS7 protocol and SS7
testing, and also elaborates on the need to automate the testing process. Chapter 3 develops a
methodology to analyze the test results and describes the software architecture. The essence
                                                                                            2


of the methodology consists of predicting the expected behavior of the STPs for the various
tests, and then comparing the actual behavior of the STPs during the tests to the expected
behavior. Chapter 4 provides a language to formally describe the response of STPs to the
tests. Chapter 5 explains the pre-processing of the test data and Chapter 6 describes the
matching of the expected behavior to this pre-processed data. Chapters 7 and 8 describe how
the results of the matching process is presented so as give important information in an easily
understandable format. Chapter 9 provides a conclusion, and lists future work.
                                                                                             3


2 Background
    This chapter introduces aspects of the Signaling System 7 (SS7) that are pertinent to this
thesis. Section 2.1 gives an overview of SS7 network structure and protocol and compares it
with the Internet Protocol (IP). Section 2.2 explains the concept of interoperability testing
and Section 2.3 explains the testing procedure in detail. Section 2.4 elaborates on the need to
automate interoperability testing.


2.1 SS7 Overview
2.1.1 SS7 Network Elements
SS7 defines both a network structure and a packet switched protocol suite. There are three
different kinds of network elements in an SS7 network: SSPs (Service Switching Points),
STPs (Signal Transfer Points) and SCPs (Service Control Points). Each signaling point in the
SS7 network is uniquely identified by a numeric point code. Point codes are 3 bytes long and
are carried in signaling messages exchanged between signaling points to identify the source
and destination of each message. Each signaling point uses a routing table to select the
appropriate signaling path for each message. The three kinds of network elements are shown,
using the symbols normally used to depict them, in Figure 2.1.

                                                       STP
                                     SSP
                                                                          SCP




                     Voice Trunks


                                                       STP
                                     SSP
                                                                          SCP
                                           SS7 links         SS7 links

                             Figure 2.1: SS7 network elements

These three kinds of network elements are described in the following sections:

2.1.1.1 Service Switching Point (SSP)
SSPs are switches that originate or terminate calls. An SSP sends signaling messages to other
SSPs to setup, manage, and release voice circuits required to complete a call. An SSP may
                                                                                                4


also send a query message to a centralized database (an SCP) to determine how to route a call
(e.g., a toll-free 1-800/888 call).
2.1.1.2 Signal Transfer Point (STP)
STPs are datagram switches in an SS7 network. They receive and route incoming signaling
messages towards the proper destination. They also perform specialized routing functions.
They are analogous to routers in an IP network. STPs are generally deployed in “mated
pairs” in order to provide fault tolerance.
2.1.1.3 Signal Control Point (SCP)
SCPs are databases that provide information necessary for advanced call-processing
capabilities like 1-800 calls, credit card number verification, etc.


2.1.2   SS7 Signaling Links
SS7 messages are exchanged between network elements over bi-directional signaling links
that generally operate at 56 or 64 kilobit per second (kbps). Signaling occurs out-of-band on
these dedicated links rather than in-band on voice channels. SS7 signaling links are named
according to their use in the signaling network.
                                                        STP
                           SCP                                                      SCP
                                      A                                     A

                                                        C
                                                D                 D
                                                        STP




                                 E
                                                    D         D
                                          STP                         STP
                 SSP
                            A                           B                       A         SSP


                                                                                A
                            A                           B
                       F                  C                           C


                                          STP                         STP
                 SSP        A                                                             SSP

                                                        B                       A
                             Figure 2.2: Various types of SS7 links

The SS7 link types are described below:
                                                                                           5


2.1.2.1 A Links
An "A" (access) link connects a signaling end point (e.g., an SCP or SSP) to an STP. Only
messages originating from or destined to the signaling end point are transmitted on an "A"
link.
2.1.2.2 B/D Links
A "B" (bridge) link connects an STP to another STP in the same level of the switching
network hierarchy, where as "D" (diagonal) links connect STPs that are in different levels of
the hierarchy (e.g. local and regional STPs).
2.1.2.3 C Links
A "C" (cross) link connects STPs in a mated pair. A "C" link is used only when an STP has
no other route available to a destination signaling point due to link failure(s).
2.1.2.4 E Links
An "E" (extended) link connects an SSP to an alternate STP. "E" links provide an alternate
signaling path if an SSP's "home" STP cannot be reached via an "A" link.
2.1.2.5 F Links
An "F" (fully associated) link connects two signaling end points (i.e., SSPs and SCPs).


2.1.3 Basic SS7 Network Architecture
Figure 2.3 shows an example of how the basic elements of an SS7 network are deployed to
form two interconnected networks.
                                                                                                                  6


                1                                                                             31
                          A13                                                     A43

                A14                                                                      A44

                                            D1-0,1
      SSP1      A1              STPA                                    STPC                  A31         SSP31
                A2                          D2-0,1                                            A32

       .                                                                                                    .
       .                                                                                                    .


                                C1-0,1




                                                                        C2-0,1
       .                                                                                                    .
                                          D3-0,1
             A11 A12                                                                                A41
                                STPB                                    STPD
      SSP6                                  D4-0,1                                                        SSP36
                                                                                                A42
                    A15                                                                 A45

                          A16                                                    A46
                2                                                                             32

                                         Figure 2.3 Basic SS7 network

As the SS7 network is critical to call processing, SCPs and STPs are usually deployed in
mated pair configurations in separate physical locations to ensure network-wide service in
the event of an isolated failure. The mated STPs perform identical functions. For example, in
the figure, STPs A and B and SSPs 1 and 2 are mated pairs. Links between signaling points
are also provisioned in pairs. Traffic is distributed evenly across all links in the link-set. If
one of the links fails, the signaling traffic is rerouted over another link in the link-set. The
SS7 protocol provides both error correction and retransmission capabilities to allow
continued service in the event of signaling point or link failures.


2.1.4 SS7 Protocol Stack
The SS7 protocol stack is shown in Figure 2.4 in relation with the Open Systems
Interconnect (OSI) model defined by the International Standards Organization and the
TCP/IP protocol stack.
                                                                                          7


       Application
                                   OMAP TCAP ISUP                     Application
       Presentation
          Session
                                                                     TCP/UDP etc.
         Transport                      SCCP
         Network                       MTP Level 3                          IP
        Data Link                      MTP Level 2                     Data Link

         Physical                      MTP Level 1                      Physical
            OSI                             SS7                         Internet
   Figure 2.4 SS7 Protocol layers shown in relation with the OSI model and TCP/IP
                                    protocol stack

The SS7 protocol layers are discussed in the following sections.
2.1.4.1 MTP Layers 1, 2 and 3
The Message Transfer Part (MTP) is divided into three levels. The lowest layer, MTP Level
1, is equivalent to the OSI Physical Layer. MTP Level 2 ensures reliable and accurate
transmission of a message across a signaling link. Level 2 implements flow control, message
sequence validation, and error checking. MTP Level 3 provides message routing between
signaling points in the SS7 network. MTP Level 3 re-routes traffic away from failed links
and signaling points and controls traffic when congestion occurs.
2.1.4.2 ISUP
Integrated Services Digital Network (ISDN) User Part (ISUP) user part defines the messages
and protocol used in the establishment and tear down of voice and data calls over the public
switched telephone network (PSTN).
2.1.4.3 SCCP
The signaling connection control part (SCCP) provides the capability to access different
applications (called subsystems) within a node. Examples of subsystems are 800 call
processing, calling card processing.
2.1.4.4 TCAP
Transaction Capabilities Application Part (TCAP) defines the protocol typically used to
communicate between subsystems in nodes. TCAP messages use SCCP for transport.
                                                                                                8



2.1.5 A brief review of MTP Level 3 network management
The discussion in this section is limited to the most important messages in MTP Level 3.
These are the messages that are seen most often in the SS7 testing dealt with in this thesis.
2.1.5.1 Traffic Management
Traffic management messages are used between two signaling points to divert traffic away
from failed links and also to divert traffic back to the links when they are restored. Traffic
management messages are originated by the network element (signaling point), which detects
a problem in a link, and are sent over an alternate link to inform its adjacent signaling point
of the problem. A changeover order message (COO) is used to divert traffic away from a
failed link. The signaling point that receives the COO sends a changeover acknowledgement
message (COA) and diverts the traffic to an alternate link. A changeback declaration
message (CBD) is used to divert the traffic back to a restored link. The signaling point that
receives the CBD sends a changeback acknowledgement message (CBA).
2.1.5.2 Route Management
Route management messages are used to divert traffic away from and back to a specific
signaling point. A transfer-prohibited message (TFP) is sent by a signaling point when it
determines that it can no longer reach a destination. A transfer-allowed (TFA) message is
used when a route becomes available again. This is sent by the originator of a TFP to indicate
that traffic may be sent once again to the affected signaling point. A transfer-restricted
(TFR) message is sent by an STP when it determines that messages to a particular destination
should no longer be sent through the STP unless there is no alternative. When a transfer-
prohibited or a transfer-restricted message is received by a signaling point, a timer is started
and a signaling-route-set-test message (SRST) is sent to the signaling point that originated
the TFP or TFR at the expiry of the timer. The timer is reset after the message is sent. The
SRST messages are sent until the signaling point receives a TFA. This message is sent to test
the status of a prohibited or restricted route. The SRST corresponding to a TFP is called
SRST-prohibited (RSP) message and the one corresponding to a TFR is called SRST-
restricted (RSR). A transfer-controlled message (TFC) is sent by an STP when an
application layer message destined for a route that has been marked by the STP as congested
arrives at the STP. Similar to the SRST messages, a message called signaling-route-set-
                                                                                             9


congestion-test message (RCT) is sent periodically by the signaling point that received a TFC
to the STP that sent the TFC.


2.1.6 Comparison with IP
There is a recent interest by the service providers in offering Intelligent Network based
services such as 800 numbers, virtual private networks, etc., that are currently supported by
SS7 networks in voice over IP offerings. Hence, there is an increasing convergence of the
SS7 and IP communities working on voice over IP.

   Signaling System No. 7 (SS7) networks and Internet Protocol (IP) networks are both
connectionless packet-switched networks. However, these two networks use starkly different
approaches to various tasks, such as error control, flow control, congestion control, etc.

   Two fundamental differences between the two networks that influence many of the
protocol aspects are as follows. First, IP is designed to allow diverse computer networks to
interconnect and communicate with each other i.e., to be an internetworking protocol to ride
on top of the protocol layers of other networks, while the SS7 protocol stack was designed
for a homogeneous network. This, along with other considerations like reliability in SS7
networks, leads to an emphasis toward performing functions end-to-end in IP networks (for
an example, at the TCP layer), while in SS7 networks, given that the whole protocol stack is
defined, there is reliance on the lower layer protocols for many functions. Second, IP
networks have no predefined architecture - arbitrary topologies are possible. To some extent
this is true of SS7 networks as well in that STP mated pairs can be interconnected in any
manner; however SS7 networks have the “quad architecture construct” that is used in most
configurations, which is shown in Figure 2.3. The “quad architecture construct” is one in
which two STP mated pairs are interconnected in a mesh configuration with multiple links
interconnecting the four nodes of the quad. A third difference is the goal to serve a wide
variety of applications in an IP network while SS7 applications are limited. Also, SS7 is
mainly connection-less and IP is used mostly with the connection oriented TCP.

2.1.6.1 Error control
In SS7 networks, error correction and error recovery is done on a link-by-link basis. In the
Internet Protocol stack, error correction is done on an end-to-end basis and error detection is
                                                                                              10


also done locally, in Ethernet for example. Packet loss at routers (STPs) is prevented through
a congestion control mechanism. IP allows packet losses, which are again taken care of by
the end-to-end correction mechanism of TCP. Finally, link failures are handled by a COO
procedure to retrieve messages that are in the buffers of the failed link and to retransmit these
messages on an alternate route so that they are not lost. SS7 tries to make sure that once a
message enters the SS7 network, it is sent to the destination. TCP/IP relies on end-to-end
retransmissions.
2.1.6.2 Flow control
Flow control is again performed at the link layer in SS7 using a special message, which is
sent when a signaling point detects that a link is congested. In TCP/IP protocol suite, end-to-
end flow control is achieved by TCP using a sliding window scheme.
2.1.6.3 Congestion control
Each SS7 message is assigned a congestion priority by its generating application. This is
used by the STPs to determine whether or not a message should be discarded under signaling
link congestion. Four levels of congestion priority are accommodated in the signaling
network, with 0 being the lowest and 3 the highest. There are three different sets of buffer
thresholds in SS7 – congestion onset thresholds, congestion abatement thresholds and
congestion discard thresholds. These are used to determine whether to forward or discard a
message with a given priority and whether to send a transfer-controlled message to the
originator of the message. This mechanism tries to avoid congestion while letting the more
important messages go through by reducing the traffic on detecting the onset of congestion.
       TCP tries to avoid congestion by using the slow start technique. When congestion
does take place, TCP uses the multiplicative decrease congestion avoidance technique to
ease the congestion by reducing the rate of transmission. The buffers in IP routers are
monitored as in SS7 STPs for signs of congestion. When congestion is detected or IP packets
discarded (based on the particular implementation), the earlier practice was to use the
Internet Control Message Protocol (ICMP), which is an error reporting helper protocol of IP,
to reduce congestion. ICMP Source quench messages were sent to the original sources of the
traffic to report congestion. The TCP layer of the source then acts on the source quench
message by reducing the rate of transmission. The source quench was thus similar to the
transfer-controlled message of SS7. Later research suggested that this practice consumes
                                                                                              11


network bandwidth but is an ineffective (and unfair) technique to combat congestion. Hence,
a recent Request for Comments (RFC) prohibits routers from sending ICMP source quench
messages [1].
2.1.6.4 Routing
Routing in SS7 is static. Routing tables at each signaling point are maintained by
administration personnel. SS7 networks have built-in redundancy; when a link or a node
failure occurs, the alternate routes are used. Routing in the Internet Protocol suite is dynamic.
Protocols like Exterior Gateway Protocol (EGP), Border Gateway Protocol (BGP), Routing
Information Protocol (RIP) and Open Shortest Path First (OSPF) are used to build and
automatically update routing tables.
       The IP routers use a message called the ICMP destination unreachable to tell the
source that a particular destination cannot be reached by the router. This message is similar to
the transfer-prohibited message used in SS7.


2.2 SS7 Interoperability Testing
All SS7 network elements have to be tested to make sure that they satisfy certain
requirements before they are deployed for use. This testing procedure involves several
independent tests. A set of such tests, passing all of which the network element is considered
fit to be deployed, is called a test plan. There are three important aspects to a system, such as
an STP, each of which can be tested:
   Functionality: STPs that function properly should forward signaling messages and
    perform Network Management functions. The Network Management messages that they
    send should be of the correct type and have the correct parameter settings. The relative
    times at which messages are sent indicate the timer values used in the STPs. The manner
    in which the STP distributes its load over separate links is another aspect of its
    functionality.
   Performance: The throughput of the STPs, and the delay experienced by messages are
    typical performance metrics.
   Reliability: Reliability metrics include average down-time per year, number of outages
    per year, maximum duration per outage, etc. It is difficult to determine whether reliability
                                                                                              12


      requirements are met in stress tests that only last for relatively short durations. Longer
      burn-in periods or alpha testing periods are needed to check these requirements.
      Functionality tests include (i) protocol conformance and (ii) interoperability of nodes
from different vendors. Bellcore‟s1 specification of the SS7 protocol [2] is the North
American industry standard, while the ITU‟s specification is used internationally. Testing
whether an isolated SS7 network element satisfies the specifications is termed conformance
testing, while testing the element‟s ability to interface with an SS7 network according to the
specifications is termed interoperability testing. This thesis deals with interoperability
testing.


2.3 The Testing Procedure
The overall STP testing procedure has four stages – set up, execution, data retrieval and
analysis. These are explained in more detail in the following sections.
2.3.1 Set up
The testing environment consists of the following devices:
     The STPs that are the Systems Under Test (SUTs), and devices that connect to the STPs
      (e.g. SCPs).
     Devices that create inputs to the STPs. Two types of devices create inputs:
           o Load generators that act as terminals, i.e. they act as sources and sinks of SS7
              messages.
           o Intermediate systems that perturb the messages that other devices exchange. For
              example, a noise generator that injects errors into a link.
     Monitors that observe and record the behavior of the STPs.
     Devices that may indirectly control other devices in the testing environment.
     “Glue” devices that connect the aforementioned devices, e.g. digital cross-connects,
      cables, etc.
Before a test is performed, all the devices in the testing environment are set up in the required
configuration and all the parameters are set to the required values.




1
    Now known as Telcordia
                                                                                                 13


2.3.2 Execution
After the test environment is set up, traffic generation is started, and all the actions pertaining
to the test are performed. Examples of such test actions include increasing the traffic until
congestion is reached and failing links. These actions are performed using interfaces to
devices in the test environment.
2.3.3 Data Retrieval
After all the test actions are performed, the data recorded by the monitors is retrieved and
saved. This data contains the behavior of the STPs in response to the test actions. The data is
retrieved using interfaces to the monitoring devices in the test environment.
2.3.4 Analysis
The retrieved data is analyzed to check whether the STP‟s behavior satisfies the protocol
specification or not. The analysis procedure is explained in Section 3.


2.4 Need for Automation
        During such tests, SSP emulators generate traffic to load the STPs. Each SSP must be
configured independently. The tester must manually set parameters such as the network
address of the SSP, and the type of traffic that the SSP generates (e.g. the priority, and the
length distribution of Message Signal Units). In addition to the SSP parameters, the operator
must also configure databases and routing tables in the STPs.
        To fully test a STP, it is necessary to run a suite of tests. The configuration of the
SSPs and the databases may need to be changed for different tests, and even for different
steps within a test. Furthermore, some features of the STPs may not be tested because of time
constraints.
        When an STP is tested, it sends and receives exchanges messages that need to be
collected for analysis. It is infeasible to collect all of the messages during a typical test due to
constraints on memory available to save the data. Consequently, the monitoring equipment
needs to be configured to specify which messages should be collected. This is usually done
manually through Graphical User Interfaces of the monitoring devices. These specify such
information as when to collect data, what messages to collect, and what parameters of
messages to trap.
                                                                                             14


       The size of the data collected in each test typically runs into several megabytes of
text. Manual analysis of such vast amount of data is extremely tedious and error-prone. It is
difficult to be completely accurate in the analysis. It is also possible that not all aspects of
protocol operation are verified if the analysis is done manually.
       If the above testing procedure is automated, it reduces the chance of human errors
significantly and also leads to faster deployment of the STPs in the field.
                                                                                             15


3 Overview of the Analysis Methodology and Software
     Architecture
This chapter provides an overview of the analysis methodology and software. Section 3.1
presents the analysis methodology, which forms the theoretical basis for the automation
software. Section 3.2 describes the software architecture.
3.1 Analysis Methodology
This section describes a methodology for analyzing the results of STP functionality tests. The
essence of the methodology is to use a specification of the requirements for STPs, and the
description of the test configuration and test steps, to describe the Expected Behavior of the
STPs. This is then compared to the actual behavior of the STPs during the test.
3.1.1 Introduction
To understand the methodology for analyzing test results, it is necessary to set analysis in the
context of the larger testing process. This process consists of the following stages:
1.     List the requirements that specify how the STP is to behave.
2.     Define a test plan consisting of multiple tests to exercise these requirements. Each test
       requires equipment to be arranged in a particular configuration, and certain test steps
       to be performed that force the equipment to behave in ways that will test the
       requirements. Several link monitors will observe this behavior by recording messages
       and load measurements on individual links. For example, in a configuration with two
       STPs connected by two D links, a test step may involve failing one of these links, and
       monitoring the second link.
3.     From the configuration, and the requirements, describe how the STP is expected to
       behave in response to each test step. This is called the Expected Behavior of an STP.
4.     Analysis: Compare the actual behavior as recorded by the monitors with the Expected
       Behavior.
5.     If the analysis indicates that the STP passes the test, then the process is complete.
       Otherwise, the test       cases that failed need to be recorded for generation of
       Modification Requests (MRs) to STP vendors.
                                                                                                  16


When Expected Behaviors for the tests are still being developed (in stage 3), it can be useful
to perform some actual tests that are intended more to test the correctness of the Expected
Behaviors than the correctness of the STPs “under test”. In this case, if the STP does not pass
the test, then this could be due to the Expected Behavior being inaccurate, and requiring
revision.


3.1.2 Analysis methodology
The table below shows the notation used in describing our analysis methodology.


                        Table 1 : Notation used in the analysis methodology
         At,s,m        Set of all actual events2 captured by the monitor m at step s of test t.
         Xt,s          The Expected Behavior of the STP in test t, step s.
         Mt,s          The set of all actual events that have matched to expected events.
         Ht,s          The set of all expected events that cannot be matched (hidden
                       events).
         Pt            Set of parameters and timer values implemented in an STP relevant
                       to test t
         TP            The set of all tests in the test plan
         St            The set of steps in test t
         Ms,t          The set of monitors that are used in step s of test t
         p(a)          The parameters of event a, where aAt,s, Xt,s
         (a)          The time of event a, where aAt,s
         C(a)          The set of aspects of the event that have to be compared to declare
                       equivalency to event a, where a Xt,s. An aspect is p or.


The input to the analysis process is:
     an expected test sequence Xt,s for all tTP, sSt; and
     the actual test data collected from the tests At,s,m for all tTP, sSt, mMs,t .
The expected test sequence is created before the tests are run and is a part of the software.

2
    An event is a message or a load measurement.
                                                                                              17



For all tTP, the analysis methodology consists of the following phases:
1. Extract STP parameters: The set of claimed parameter values (Pt) for the STP should be
    recorded, including timer values and the profile that indicates optional features
    implemented in the STP. These values will be checked with the actual observed
    parameter values as a part of the analysis.
2. Filter, format and combine the actual test data: All information that is not pertinent to the
    test in At,s,m for all mMs,t is filtered out. For example, records of information from point
    codes that are of no interest are removed. The actual data At,s,m collected at different
    monitors could be in different formats and so may need to be reformatted. All the At,s,m
    are combined into one data base At,s that has just one format to represent events.
3. For each step of the test, i.e. for all sSt
      I. Obtain the time of the test step: This is required because the analysis software needs
          a specific time from where to start the matching process. All expected events Xt,s
          will be matched in the time interval given by this time and the time of the next test
          step.
     II. Match actual events to expected events: xiXt,s search At,s for an event that
          matches criterion C(xi). If it is not possible to match the event xi because the a
          monitor was not placed to record the corresponding event, then the event xi should
          be added to the list of hidden events (Ht,s). If there is a temporal relationship
          between xk and xl (not necessarily consecutive events), then the same temporal
          relationship must hold between the corresponding events in At,s. For example, if
          expected events xk and xl correspond to actual events ak and al, and if xk causes xl,
          then the relation (al)> (ak) must hold. The expected events do not have a fixed
          sequence because an STP may be required to generate multiple messages in
          response to a test step action and the exact sequence of these messages is not always
          predictable. If any observations of STP parameters can be made during this
          matching process, they should be noted in OPt.
    III. Record matched events: Each actual event ai that matched to an expected event xi in
          step I should be added to the set of matched actual events, Mt,s.
                                                                                              18


4. Note missing events: Any expected events that have not been matched to an actual event
   (i.e. Mt,s \ (Mt,s  At,s)) constitute missing events.
5. Note unexpected events: Any actual events that have not been matched to an expected
   event (i.e. At,s \ (At,s  Mt,s)) constitute unexpected events.
6. Check the observed STP parameters: Check that the observed STP parameters (OPt)
   match the claimed parameter values (Pt).
7. Conclusion of analysis: The system is considered to have failed the test if:
      I. There are any missing events, AND/OR
     II. There are any unexpected events
    If there are no missing events and no unexpected events but there are hidden events, the
    test is considered to be inconclusive.
    The system is considered to have passed the test if it did not fail and if the result was not
    inconclusive.


3.2 Overview of Automated SS7 Test Results Analyzer (ASTRA)
The software that implements the methodology presented in the previous section is called
Automated SS7 Test Results Analyzer (ASTRA). Figure 3.1 provides the architecture of this
software and summarizes the flow of data during automated testing. It indicates the different
types of data involved in test automation, and the software components that process that data.
The vertical dimension reflects time, and data propagates downwards.
                                                                                                   19



                                                         Test Network Config.
      Monitor Data 1            Link Mapping File

           :::
                                                                               Expected Behavior
      Monitor Data n                 Point Code Assignment



Clock Differences File                    Recorded Times of Test
                                                 Actions



                                                    Replacing
                    Data Formatter                   library                       Translator




                                Actual Event Record



                 Matching                           Specific Analyzer
                  library




             Matched Event Rcrd         Missing Event List              Param Obs. List



             Event Summarizer          Expanded Expected            Hidden Event List
                                           Behavior


     Unex‟ted Event List         Event Number File

                                                                Report Generator
             Key:
            Process


             Data                                                  Test Report


           Function
           Library

                            Figure 3.1 ASTRA software architecture
                                                                                                20


       The automated analysis software consists of five main parts: the Expected Behavior
files, the Data Formatter, the Translator, the Event Summarizer and the Report Generator.
The Expected Behavior is the predicted response of the STPs to the test actions. This
Expected Behavior is compared to the actual response of the STPs (saved in the collected
data), which forms the core of the analysis procedure. A format to express the Expected
Behavior in a machine-understandable form is required and this format is presented in
section 4. The role of the Data Formatter is to convert the data collected during the test into a
form suitable for automated analysis. The Formatter is explained in detail in section 5. The
Expected Behavior is converted into an executable program called the Specific Analyzer by
the Translator. The executable program uses a library of matching functions to compare the
Expected Behavior with the actual data. The complete matching process is explained in detail
in section 6. This matching process produces various intermediate results, which are
processed and a final output is produced. The processing is done by the Event Summarizer
(section 7) and the Report Generator (section 8). All the programs and the data files follow
the naming scheme given in Appendix A: File naming scheme and will be placed according
to the file system structure given in Appendix B: File structure format.
       Section 0 discusses the naming scheme used for the test network components in
ASTRA. Section 3.2.2 discusses the various input data files that are used by ASTRA. Section
3.2.3 addresses the selection of a suitable programming language for ASTRA.


3.2.1 Naming scheme for configuration components
The Expected Behavior consists of events that relate to the entities involved in the test, for
example, STPs, SSPs, SCPs or links in the test environment. So, it is important to define a
scheme for naming the nodes and links in the test environment. For interoperability testing,
the test environment consists of two areas (called areas East and West), and the test is of
interoperability of the STPs in the two areas. In the example network configuration shown in
Figure 2.3, area East is the right half of the figure and area West is the left half of the figure.
The STPs in different areas are usually from different manufacturers. The STPs in area East
are always called STP_A and STP_B and the STPs in area West are always named STP_C
and STP_D. The SSPs in area East are named SSP_E1 – SSP_Es1, and SSPs in area West are
named SSP_W1 – SSP_Ws2, where s1 and s2 are the numbers of SSPs in areas East and West
                                                                                             21


respectively. SCPs in area East are named as SCP_E1 – SCP_Ec1, and SCPs in area West as
SCP_W1 – SCP_Wc2, where c1 and c2 are the numbers of SCPs in areas East and West
respectively. Sometimes groups of SSPs, called clusters, are referred to in the tests. The SSP
cluster in the area East is named SSPs_E and the SSP cluster in the area West is named
SSPs_W.
       The following convention is used in naming the links: the name of a link connecting
node1 to node2 consists of the type of the link, node1, node2 and, unless there is only one
link in the link-set connecting nodes node1 and node2, the number of the link in the link set
that connects these two nodes. For example in the network configuration shown in Figure
2.3, the link connecting SCP_E1 to STP_A is named A(SCP_E1)(STP_A). Similarly the first
D link in the link-set connecting STP_A and STP_D would be named D(STP_A)(STP_D)(0).
If not all of these four parts of the link name are specified, then the name refers to all the
links that have these parts in common, which we call a link group. For example, the link
group D(STP_A)(STP_D) refers to both D(STP_A)(STP_D)(0) and D(STP_A)(STP_D)(1),
D(STP_A) refers to all D links from STP_A.


3.2.2 Inputs to the software
This section describes in detail the inputs needed to perform the analysis. These inputs
include monitored data, timing information, information about the test environment and
information needed to unify the different monitored data files.
3.2.2.1 Monitored Data
There could be several monitoring devices used in a test, each of which will result in a data
file. These could represent the events in different formats and use different clocks to time
stamp the events. Each file thus saved will have a corresponding format used to represent the
events and is to be assigned an identifier that will be used in the naming of the file. The file
with a particular format and an identifier is to be named „testxx_identifier.format‟, where xx
is the number of the test in the test plan, which has been performed. For example, if four files
were saved for the test numbered 12, the first two with the format fmt1 and the other two
with the format fmt2, and the identifiers MACHINE1, MACHINE2, MACHINE3 and
MACHINE4 have been assigned to them in order, the files will be named as follows:
test12_MACHINE1.fmt1,
                                                                                               22


test12_MACHINE2.fmt1,
test12_MACHINE3.fmt2, and
test12_MACHINE4.fmt2
The extension of the file name tells the software the format of the events in the file and the
identifier is used along with the Clock Differences File (section 3.2.2.2) to synchronize the
events in all the files to one standard clock.
The software is designed to understand only a few known formats. If a new format is to be
used, then additional code to understand this format is to be added to the software. The
monitored data files must contain data starting from some time before the test starts and
ending at some time after the test completes.
3.2.2.2 Clock Differences File
The Clock Differences File contains one line for each test data file. Each line has two fields.
The first field is the identifier used in the file name and the second field is the difference, in
seconds and milliseconds, between the standard clock and the clock used in the file. The
standard clock is the one used to generate the Recorded Times of Test Actions (section
3.2.2.4) for the particular test. For example, if at the same instant, the clocks used in
generating       the       files       test12_MACHINE1.fmt1,           test12_MACHINE2.fmt1,
test12_MACHINE3.fmt2 and test12_MACHINE4.fmt2 were 12:39:57.865, 11:34:13.899,
18:23:50.867 and 12:39:54.028 respectively and the clock used to produce the RTA was the
same as the one for MACHINE1, the clock differences file is shown below:


identifier             (standard clock) – (local clock)
MACHINE1                       0
MACHINE2                       3943.966
MACHINE3                       -20633.002
MACHINE4                       3.867



3.2.2.3 Test Action List
As discussed in the previous sections, SS7 performs most functions on a link-by-link basis.
The important interoperability issues are how the signaling points initialize the network and
how they react to link failures and network congestion etc. Hence, the actions to be
performed in the interoperability testing are mostly failing and restoring links and starting
                                                                                             23


and stopping traffic at the SSPs. The test actions are provided with standard names and
formats that are used to represent them in a machine-readable format. The following are all
the test actions that are used in STP interoperability testing and the generic format used for
them.
1. Beginning and end of test
   The test action test_begin refers to the completion of the set-up stage of the test. The test
   action test_end refers to the completion of the test.
2. Failing and restoring links
   Failing and restoring links are the most commonly occurring steps in the tests. The
   generic command for failing a link is given below:
   fail_link(link_name)
   link_name – Name of the link to be failed


   The generic command for restoring a link is given below:
   restore_link(link_name)
   link_name – Name of the link to be restored


3. Traffic control
   Commands are needed to control the traffic at individual SSPs (real or emulated). The
   commands block_ssp and unblock_ssp respectively stop and start the traffic at the
   specified SSP.
   block_ssp(ssp_name)
   ssp_name – name of the SSP at which the traffic is to be stopped.


   unblock_ssp (ssp_name)
   ssp_name – name of the SSP at which the traffic is to be started.


4. Restarting an STP
   Some tests require that the STP be shutdown and restarted. The generic name for this is
   given below
   restart_stp (stp_name)
                                                                                               24


    stp_name – name of the STP that is to be restarted.


The Test Action List is not directly used by the analysis software but is used to generate the
Recorded Times of Test Actions, described in the following section. The Test Action List is a
text file with a machine-readable format. The file will contain a line for each action of the
test. Each line contains:
   An optional label, followed by a colon. These labels are explained in the section 4.1.1.5.
    When the test action in the line is executed, the label is assigned the time at which the test
    action is executed.
   A Generic Test Action.
The first line of the Test Action List must be:
       $beginning_of_test: test_begin()
The last line of the Test Action List must be:
       $end_of_test: test_end()
Figure 3.2 provides an excerpt from a typical Test Action List, in this case failing the A links
that connect SSPs to STP_A. The naming scheme used to represent the nodes in the test
network is given in section 0.
$ta_fail{A(SSP_E1)(STP_A)}: fail(A(SSP_E1)(STP_A));
$ta_fail{A(SSP_E2)(STP_A)}: fail(A(SSP_E2)(STP_A));
$ta_fail{A(SSP_E3)(STP_A)}: fail(A(SSP_E3)(STP_A));
       …
                            Figure 3.2: Excerpt of a Test Action List.

3.2.2.4 Recorded Times of Test Actions
A test is executed by performing the actions described in the Test Action List for that test.
The time when action in the Test Action List is performed is recorded to create the Recorded
Times of Test Actions. This is a text file, with each line starting with the time at which the
action on a line of the Test Action List was executed, and the remainder of the line echoing
the description of the action from the Test Action List. The Recorded Times of Test Actions
record the actions in chronological order. Figure 3.3 provides an example of an excerpt from
                                                                                               25


a Recorded Times of Test Actions file, corresponding to the Test Action List shown in Figure
3.2.


0:01:00          $ta_fail{A(SSP_E1)(STP_A)}: fail(A(SSP_E1)(STP_A));
0:03:00          ta_fail{$A(SSP_E2)(STP_A)}: fail(A(SSP_E2)(STP_A));
0:05:00          ta_fail{A(SSP_E3)(STP_A)}: fail(A(SSP_E3)(STP_A));
          …
                Figure 3.3: Excerpt of a Recorded Times of Test Actions file.


3.2.2.5 Test Network Configuration
          All tests in any STP interoperability test plan use a quad as the core of the Test
Network Configuration (TNC). There are 2 mated pairs of STPs, s1 SSPs in area East, s2
SSPs in area West, c1 SCPs in area 1 and c2 SCPs in area 2. There will sometimes be other
STPs/SSPs/SCPs connected to one or both STP mated pairs.
          The TNC file specifies the topology of the test network, i.e. the type of nodes and
links involved in the test, how they are connected, and the names of these nodes and links.
Because the link naming system indicates the nodes that connect to the link, a definition of
the TNC only requires a list of the link names.
          Each line of the TNC file defines a link in the network. Appendix C: Example Test
Network Configuration provides a sample TNC file that describes the network configuration
given in Figure 2.3 Basic SS7 network. Note that links are assumed to be bi-directional, and
each link is listed only once, with the nodes that it joins specified in alphabetical order. For
example, there is an “A(SSP_W3)(STP_D)(0)” link, but no “A(STP_D)(SSP_W3)(0)” link.


3.2.2.6 Point code Assignment
The point codes assignment file (PAF), gives the names of all the nodes in the test network
configuration according to the naming scheme given in 0 and the corresponding point codes
assigned to the nodes for the test. The file contains as many lines as there are nodes in the test
network configuration. The name and the point code is separated by white space (single
spaces and/or tabs). The point code must follow a 9-digit format with a hyphen after the third
digit and another hyphen after the sixth digit. For example: 246-024-001.
                                                                                              26


An excerpt from a PAF is shown below:
Node Name        Point Code
STP_C          246-242-000
STP_D          246-243-000
SSP_E1         246-004-001
SSP_E2         246-004-002


3.2.2.7 Link name mapping
    The Link Mapping File gives the mapping between the link names, as given in section 0
and the special names used in the different files as given in section 3.2.2.1 to refer to these
links in the monitored test data, for all the links monitored.
    Each line of the LMF starts with the identifier part of the file that contains the monitored
data (see Section 3.2.2.1). Note that all such identifiers should be different from each other.
Spaces and/or tabs separate subsequent fields on the line. The second field in the line is the
special name used in that file to refer to a particular link in the direction toward a particular
node connected to the link. The link and the node form the third and fourth fields of the LMF
file respectively. This file is used to convert all the data files to the same format and also
provides the list of all the monitored links.


3.2.3   Choice of the programming Language
    As was discussed in Section 2.4, the testing procedure involves processing large amount
of textual information. Perl is a high-level programming language with powerful text
manipulation facilities. Perl is portable and can be used on popular operating systems like
Windows, Unix and Linux. It is also a simple programming language and not as syntactically
rigorous as C, which reduces the development effort. Though Perl programs often are slower
than their counterparts written in C, this is not important because the automation software is
not computation intensive. The time taken is usually a few minutes to analyze the results of a
test that takes a few hours to perform. In view of the above-mentioned reasons, Perl is chosen
as the programming language for ASTRA.
27
                                                                                             28


4 Expressing the Expected Behavior for Automation
        To automate analysis of the test results data, the Expected Behavior of the STP needs
to be expressed in a machine-readable form. The Expected Behavior is a consequence of the
test actions. For example, we may expect a test action that fails a link to cause a STP to issue
a TFR message. Therefore, the Expected Behavior needs to be expressed in a manner that
also shows how the expected events relate to the test actions. For example, we need to verify
that the STP issued the TFR message in response to the link failure; the TFR message should
not occur before the link was failed, and should occur before the next test action. Each test
action is expected to cause certain responses from the STPs, and these responses may in turn
trigger additional subsequent responses from the STPs. For example, the test action of failing
an A link connecting an SSP to STP A is expected to cause STP A to send TFR messages to
both STP C and STP D, and this will, in turn, cause STPs C and D to stop using routes
through STP A. Thus, the Expected Behavior in response to a test action can be considered to
be a tree of causation, with the test action at the root of the tree, and the event(s) that that
action causes at the next level of the tree, and the events that those events cause at the next
level of the tree, and so on.
        Unfortunately, for the analyst, the ordering of some events is not fixed. Continuing
the example, the order in which STP A sends TFR messages to STPs C and D is not defined.
The formal description of the test needs to state that the link failure causes STP A to send the
TFR messages to STPs C and D, but it must not state that it causes STP A to send a TFR to
STP C and then a TFR to STP D, since a STP that conforms to the requirements could
instead send a TFR to STP D and then a TFR to STP C. Consequently, the Expected
Behavior cannot be expressed in a linear form, but needs to be expressed as a tree. In textual
machine-readable form, this can be achieved by writing one event on each line, assigning
events identifiers (line numbers), and indicating for each event which other events that event
causes. There is no need to distinguish between test action events and other events, since
both types of events can cause other events.
        The Expected Behavior consists of a list of test actions (in the order in which they are
performed), and for each test action, there is a list of the events that the test action
immediately causes. Each event describes a specific instance of Expected Behavior, and lists
the subsequent events that that event causes. Comments can be placed by beginning a line
                                                                                                 29


with a „#‟ sign. The whole line after this sign will be considered to be a comment. Section
4.1 describes the format used to express the Expected Behavior and section 4.2 gives an
example of an Expected Behavior.


4.1 Expected Behavior Format
        This section describes in depth the format for expressing the Expected Behavior that
drives the analysis process. The name “SS7 Expected Behavior Expression Language
(SEBEL)” is used to refer to this format. The Expected Behavior is described in terms of a
numbered list of events, with each event indicating the numbers of any other events that it
causes. Generally, events earlier in the list cause events that are later in the list, but this
arrangement is not always possible since one event can cause multiple follow-on events.
      As mentioned before, the Expected Behavior consists of events that relate to the
entities involved in the test. For example, the Expected Behavior may include an event in
which STP_D sends an RSM message to STP_A, which is routed through link-set
D(STP_A)(STP_C). The entities involved in that event are STP_D, STP_A, and link-set
D(STP_A)(STP_C). The type of event is that we expect an RSM message to be found.
Section 4.1.1 introduces the identifiers that identify entities involved in the events (Section
4.1.1.1), and the variables and labels that are used in the control mechanisms (Section 4.1.1.4
and 4.1.1.5). Section 4.1.2 describes the constructs that express the timing relationships
between events, while Section 4.1.3 describes the control mechanisms. Sections 4.1.4 and
4.1.5 describe the Test Action and Expected Behavior events themselves.


4.1.1 Identifiers
The Expected Behavior includes identifiers for the entities involved in the events (Section
4.1.1.1), defining and modifying sets of entities (Sections 4.1.1.2 and 4.1.1.3), variables that
control events (Section 4.1.1.4), and labels, which indicate the time of events (Section
4.1.1.5).


4.1.1.1 Entities involved in the events
Identifiers for entities involved in the test consist of strings of uppercase characters, digits, or
underscores. They do not include white space (e.g. “SSP 1”) in order to assist the software
                                                                                             30


parse the Expected Behavior. Identifiers exist for individual nodes and links in the test
environment as described in section 0, e.g. SSP_E1, STP_A, etc and D(STP_A)(STP_C)(0),
etc.
4.1.1.2 Defining a set
Sets of entities are used in control structures (described in Section 4.1.3) to define a set of
values that a variable iterator will assume. A set of n elements is defined using a statement of
the following form:
        @set_name = (elem1, elem2, … elemn);
For example:
        @SCPS_E = (SCP_E1, SCP_E2);
This form matches the form used to define lists under the computer language Perl, which is
used for automating the analysis.
4.1.1.3 Shifting a set
While expressing the Expected Behavior, it is sometimes needed that sets of entities change
for each iteration in a control structure. This is achieved using the shift command.
        The shift command removes the first element from a set, and shifts all other
elements (if any) so that they occupy the position of their predecessor in the set. The syntax
of the shift command is:
        shift @set_name;

This syntax follows the syntax of Perl‟s shift function.
        Since shift changes the set being manipulated, it should only be applied to sets that
are copies of other sets. For example, a foreach loop (explained in section 4.1.3.2.1) that
fails a set of links may need to check the type of traffic flowing on the remaining non-failed
links. This can be achieved by defining, before the foreach loop, a set @tmp_set that is a
copy of the set of SSPs whose links will be failed (e.g. @SSPS_E). The foreach loop can then
fail each link connecting to an SSP in the set @SSPS_E, and inside the loop, we can check the
traffic flowing on the @tmp_set of links, and shift this @tmp_set for each iteration of the
loop.
4.1.1.4 Variables
Variables are identified by a $ sign (a requirement that stems from Perl) followed by a string
of lowercase letters, digits, or underscores. Each variable is declared within a control
                                                                                                 31


structure (such as “foreach” section 4.1.3.2.1), and its value is assigned when the Specific
Analyzer interprets that control structure. Its value is available to be used by statements in the
scope of the control structure that declares it. For example, in the lines:
       foreach $k (@SSPS_E) {
         $ta_fail{A($k)(STP_A)}: fail(A($k)(STP_A));
$k is a variable, and would assume the values identifying the SSPs in area East. That is, $k
would assume the values SSP_E1, SSP_E2, SSP_E3, …SSP_E6. When a reference is made
to a variable, such as fail(A($k)(STP_A)), then the value of that variable is used. For example,
this loop would fail all the A links that connect SSPs in area East to STP A.
The variable “$time” equals the time of the event in the monitored data that the Specific
Analyzer (Section 6.2) is currently attempting to match to the target.
4.1.1.5 Labels
Any text before a colon in a statement in the Expected Behavior (or Test Action List)
provides a label for that statement. A label is identified by a string of lowercase letters, digits,
or underscores. The label must start with a $ sign. Subsequent references to the label in the
Expected Behavior return the time at which the labeled statement occurred in the monitored
data or the RTA file. Labels are used to express the timing relationships between events.
      When a label occurs inside a loop, and a separate value of that label is required for each
iteration of the loop, then the label should be followed by the loop variable in an expression
that is enclosed in braces. For example:
      $ta_fail{$k}: fail($k); causes 8, 29
Here, $k is the loop iterator, and for each loop, a new value of $ta_fail will be created.


4.1.2 Timing relationships between events
The waitfor() command is used to describe timing relations for Expected Behavior events.
4.1.2.1 waitfor(t, node)
The waitfor pseudo-event always causes at least one other event after a time t. The time t is
often expressed in terms of a timer parameter of a node (node), e.g. an STP, whose effective
value is unknown to the tester. The Specific Analyzer finds the event that the waitfor
pseudo-event causes, and uses the time of that event to make an observation about the STP
parameter. A waitfor() may exist within a control structure, such as a while() loop. For
                                                                                           32


example, the following excerpt describes the expectation that STP_D will send an RSM
message on link D(STP_A)(STP_D) to STP_A every T10 seconds until a route to SSP $s
becomes available (when link $k, connecting SSP $s to STP_A, is restored).
1. while($time<$ta_restore[A($s)(STP_A)]) {
2.       waitfor(T10, STP_D) causes 3
3.       findmsg(D(STP_A)(STP_D), STP_A, $s, RSM)
     }


4.1.3 Control mechanisms
Control mechanisms determine how the Specific Analyzer will set state variables, and how
many times (and with what state variable settings), it will ask the Matching Library functions
to match each event. There are two types of control mechanisms: conditional statements, and
loops.


4.1.3.1 Conditional statements
The Expected Behavior for a test may depend on the implementation of certain elements of
the network configuration other than the STPs. In particular, when a commonly used
emulator is used to emulate SSPs, it does not respond to network management messages
from the STPs, so an STP would be expected to send a series of TFR messages to an
emulated SSP (which ignores the TFR messages), whereas it would be expected to only send
one TFR to a real SSP (which would abide by the TFR message). To ensure that the
Expected Behavior descriptions require minimal maintenance, it is preferable that there be
one Expected Behavior file for all possible configurations, and that the Expected Behavior be
configurable so that it expresses the behavior that is expected for the particular
implementation of nodes used in a particular test. To accommodate this, each line of the
Expected Behavior can end with a string “//” followed by a string of characters. The string of
characters should specify the type of test configuration for which this line of the Expected
Behavior should occur. The string of characters “REAL_SSPS” indicates that the Expected
Behavior is specific to when the SSPs are implemented using real SSPs. Similarly when an
emulator of brand XXX is used to emulate the SSPs, each line of the Expected Behavior that
is specific to this emulation is followed by the string “//XXX”.
                                                                                            33


For example:
1.     findmsg(D(STP_A)(STP_D), STP_D, STP A, $s, TFR, SLC = $k) causes 2, 4, 7
2. …
3. …
4. while($time<$ta_restore[A($s)(STP_A)]) {            //XXX
5. findmsg(D(STP_A)(STP_D), STP_D, STP A, $s, TFR, SLC = $k)                   //XXX
6. }     //XXX


7.     while($time<$ta_restore[A($s)(STP_A)]) {
8.      waitfor( …


In this example, lines 4-6 are specific to the emulator XXX. If the emulator is not used, then
these lines are considered to be comments and will be ignored.


4.1.3.2 Loops
A loop allows a process (described by a compound statement which is encapsulated in braces
{}) to be repeated until a certain condition occurs. Each repeat of the loop is called an
“iteration”, and the variable that controls the loop is called the “iterator”. A loop cannot be
listed as causing other events.
The analysis requires two types of loops:
    foreach expansion: A certain process may need to be repeated for all entities belonging
     to a certain set. E.g. for each link i connecting STP A and STP B, fail link i.
    while loop: Used to indicate that an event repeats until another event occurs.

4.1.3.2.1 foreach
foreach $iterator    (@set) {
…
}
                                                                                             34


Foreach    loops repeat the code in the compound statement for all values of $iterator which
are elements of @set. The syntax of the foreach statement has been designed to correspond
to that of the foreach statement in Perl.
For example:
       foreach    $s (@SSPS_E){
                …
       }
means: “For each SSP in the set of Eastern SSPs, execute the compound statement.” The set
of Eastern SSPs might include SSP_E1, SSP_E2, SSP_E3 … SSP_E6.
When loops are nested, the different loops should have different iterator variables, e.g. $s and
$t.

4.1.3.2.2 while
while($time<$limit)   {…}
When the Specific Analyzer encounters a while loop, it offers the statements in the
compound statement repeatedly to the Matching Library functions, and specifies an upper
bound on the range for searching for matches for the events.


4.1.4 Test Action events
Test Action events are used to perturb the STP. The list of test actions that can be used in the
Expected Behavior is given Section 3.2.2.3.


4.1.5 Expected behavior
The Expected Behavior is stated in terms of two types of expected events: messages and load
measurements (Section 4.1.5.1 and Section 4.1.5.2).


4.1.5.1 Expected events
findmsg(k, dst, opc, dpc, m [, p1, p2, ...]) - returns true if a message of type m, with a
particular Originating Point Code (OPC) and Destination Point Code (DPC), is detected
flowing on link k toward node dst (which connects to link k). Depending on the type of the
                                                                                            35


message, it may contain additional parameters. Appendix D: Allowable message types and
parameters for findmsg() lists the allowable message types, and the relevant parameters.
       Usually, findmsg is applied to check that a node n1 sends a certain message to
another node n2, and we don‟t care about how the message travels from n1 to n2. In this
case, the specification of the link is usually redundant. However, the link specification is
important when we want to check the routing of messages, e.g. n1 and n2 may be SSPs and
we want to check which D link (between STPs) they are routed across. Note that n1 and n2
need not be directly connected by a link, but may be connected to links that are joined by
intermediate systems, so it is necessary to identify the link as well as the communicating
nodes. For example, we might be interested in finding a message sent from SSP_E1 to
SSP_W1, which must flow through one of the STPs.
       Findmsg()    only searches the test results for a message as far as the time of the next
step of the Test Action List.

4.1.5.1.1 Wildcards
A wildcard (“*”) can be used with findmsg() to denote any entity of the type (node, link, or
message type) required by the context. Wildcards are used to direct the Matching Library
function to ignore a field. For example, if we want to check if STP_A sends a priority 1 TFC
message to any SSP, we could use: findmsg(*,*,STP_A,*,TFC,1). When a wildcard
appears in the message type (m) field of findmsg(), then there can be no parameters (p1, p2
…) for the findmsg().


4.1.5.2 assert_load
assert_load(k, d, value) is used to check that the load on link k, in the direction towards
destination node d equals value, as a percentage of the link capacity.
E.g. assert_load(D(STP_A)(STP_C), STP_C, 10.25) is used to check that the load on each of
the two links D(STP_A)(STP_C)(0) and D(STP_A)(STP_C)(1) is 10.25 percent of the
maximum supported load.
                                                                                          36


4.2 Example of Expected Behavior for a test
This section provides an example of the machine-readable representation of the Expected
Behavior of the STPs for a test. The test in question involves cumulative and sequential link
failures. We only cover enough steps of the test to provide an overview of the description of
the Expected Behavior. In the following, text in italics refers to Test Actions. Other text
refers to the Expected Behavior, confirming that the system is behaving properly. The first
column gives the Expected Behavior in natural language and the second column gives the
Expected Behavior in SEBEL.
                                                                                                                          37


       Natural language description of the test                              Formal description of the test

1.  Define the set of all SSPs and SCPs in area East        @SSPS_E=(SSP_E1, SSP_E2, SSP_E3, SSP_E4, SSP_E5, SSP_E6,
2.  Define a copy of above set.                             SCP_E1, SCP_E2)
                                                            @set_1=(SSP_E1, SSP_E2, SSP_E3, SSP_E4, SSP_E5, SSP_E6, SCP_E1,
3.  Set up the network and start the traffic                SCP_E2)
4.  Check that the load on each of the D links connecting   1. $beginning_of_test: test_begin() causes 2,3
    STP_A to STP_C and STP_D is 10 percent of the           2. assert_load(D(STP_A)(STP_C), STP_C, 10)
    maximum                                                 3. assert_load(D(STP_A)(STP_C), STP_A, 10)
5. Fail A links from STPA connected to the SSPs             4. foreach $s (@SSPS_E) {
    sequentially (2 minutes apart).                         5.     $ta_fail{$s}: fail_link(A(STP_A)($s)) causes 6, 7, 9
6. Modify set_1.                                            6.     shift @set_1
7. STP_A sends a COO message to SSP connected to            7.     findmsg(C(STP_A)(STP_B), STP_B, STP_A, $s, COO,
    the failed link, through the C link connecting to             A(STP_A)($s)) causes 8
    STP_B.                                                  8.       findmsg(A(STP_B)($s), $s, STP_A, $s, COO,
8. The COO message proceeds to that SSP over an A                 A(STP_A)($s))
    link from STP_B.                                        9.       waitfor(T11, STP_A, $ta_restore{$s}) causes 10, 13
9. The timer T11 is started at STP_A                        10.      foreach $t (@set_1) {
10. STP A sends TFR messages to nodes in set_1              11.         findmsg(A(STP_A)($t), $t, STP_A, $t, TFR, $s)
    pertaining to the failed link after the expiry of the   12.      }
    timer T11.                                              13.   findmsg(D(STP_A)(STP_D), STP_D, STP_A, STP_D,
11. STP_A sends a TFR message to STP_D after the                  TFR, $s) causes 14
    expiry of timer T11.                                    14.      while($time<$ta_restore{$s}) {
12. STP_D starts timer T10                                  15.          waitfor(T10, STP_D, $ta_restore{$s}) causes 16
13. STP_D sends RSR message to STP_A in response to         16.          findmsg(D(STP_A)(STP_D), STP_A, STP_D,
    the TFR after every expiry of timer T10 and resets            STP_A, RSR, $s)
    the timer T10 until the link is restored                17.      }

                                                            ………..
                                                            ………..
                                                                                             38


5 Data Formatting
After performing the tests, data is retrieved from the various test elements in the form of text
files. Each data file consists of messages and other events monitored at the test element,
listed out in chronological order. Each test element can have data corresponding to more than
one node. Before the analysis software can use this data needs to be formatted in several
ways. This formatting process involves filtering, abstraction, consistency, integration, and
preparation for analysis, as described in the following sections. The formatter produces one
output file called the Actual Event Record.


5.1 Description
5.1.1 Filtering
The filtering step of formatting eliminates information in the monitored data that is known to
be irrelevant to the analysis. For example, it is a time-consuming process to set up the STP
databases, so often the databases are left containing information about how to route to point
codes that will not be involved in a specific test, and consequently STPs log information for
point codes not involved in test. The filtering stage would eliminate from the monitored STP
data any reference to point codes that are not involved in the test.
5.1.2 Abstraction to form Generic Events
The analysis is designed to be independent of the implementation of the STP so that it can be
applied to STPs from different vendors. In order to do this, it may be necessary to abstract
from the specific events that monitors record in data files to a set of Generic Events. For
example, the analysis may be interested in determining whether a particular message was
observed on a certain link. However, the actual link monitors used in a test from different
vendors may indicate the message in different ways in their files. The purpose of the
abstraction step of formatting is to translate events that relate to specific implementations of
equipment in the test environment into Generic Events that are used for analysis.
5.1.3 Establishing consistency
In order to analyze series of events that are observed across different monitors (e.g. checking
that an STP reroutes traffic in response to receiving a Transfer Prohibited (TFP) message), it
is important to have consistency in how separate monitors record events. One aspect of
consistency is that of time stamps. The formatting stage may also have to ensure other
                                                                                             39


aspects of consistency, e.g. consistency of link names in records. To help with this, the Link
Mapping File (LMF) provides the mapping between link names used by each link monitor
and the standard link naming scheme used in the Expected Behavior.              Section 3.2.2.7
describes the format of the LMF. The Formatter also records the names of links for which
there is a mapping in the LMF, in the Actual Event Record so that the Specific Analyzer can
log events that were expected on links that were not monitored, in the Hidden Event List.
5.1.4 Integration of event records
After filtering, abstraction, and establishing consistency, the individual data files from
different monitors need to be integrated to form a single Actual Event Record. Such
integration will facilitate searching during the analysis phase. The combined Actual Event
Record will chronologically list all events that occurred in the test environment during the
test.
5.1.5 Preparing for analysis
Each event should have associated with it a field so that the analysis software can check off
the event when it has been processed. We call this field the “Match” flag. By checking off
events that are expected, events that were unexpected can also be identified, as will be
described in Section 6.3.3.


5.2 Implementation
The Formatter performs the following functions.

1.      Listing of all monitored links: In some tests, only a subset of the links may be
        monitored. This may be due to a shortage of monitoring equipment, or operator error.
        The analysis software should know which links were not monitored. Hence, the
        Specific Analyzer expects that the initial lines of the Actual Event Record will contain
        a listing of all monitored links, and will record any event that is expected to occur on
        other links in a Hidden Event List file.
2.      Conversion of time stamp format: Each event in the data files contains a time stamp,
        which specifies the time at which the event was observed according to the local clock
        at the test element. The time stamps in the data files obtained from all the test
        elements are in a „hours:minutes:seconds.millisecond’ format. For example, an event
                                                                                           40


     from a file named test58_MACHINE1.fmt1 may have a time stamp 13:14:53.643,
     meaning that the time of occurrence of the event was 13 hours, 14 minutes and
     53.643 seconds, according to the MACHINE1 clock. To simplify arithmetic in the
     Specific Analyzer, which has to work with time differences, the Formatter converts
     time stamps to a „seconds.milliseconds’ format. The conversion is performed as per
     the following equation:
                  time(converted)=hours*3600+minutes*60+seconds.milliseconds
     After such a conversion, the example time stamp will be 47693.643 seconds. The
     Formatter assumes that tests do not run around midnight, in which case earlier events
     might appear to have larger time stamps than later events, as date is not considered in
     the calculations.
3.   Synchronization of time stamps: During the execution of a test, the clocks on the test
     elements could be out of synchronization. The automated analysis software needs to
     adjust the time stamps to account for the lack of synchronization. Therefore, the
     Formatter modifies all the time stamps so that they refer to one standard clock. The
     standard clock is the one that is used to produce the Recorded Times of Test Actions.
     The Clock Differences file is used to achieve the synchronization.
4.   Standardization of point codes: Different test elements use different formats to
     represent the point codes of the network nodes. For example, the point code 246-22-1
     could be represented as „246 22 1‟ in the data file of one type of monitor, and as „246-
     22-1‟ in a data file of another type of monitor. The Formatter converts all point codes
     to the standard format of the form „246-022-001‟, which makes the pattern used to
     find a point code well defined („three digits‟-„three digits‟-„three digits‟).
5.   Filtering of irrelevant information:
     5.1     Point code based: Data files might include information that is irrelevant to the
             test under consideration. So, as explained in section 5.1.1, the data is filtered
             based on the point codes relevant to the test.
     5.2     Message type based: The link monitors are normally set to collect messages of
             specific types, for example MTP Layer 3 network management messages. But
             there still remain some messages that we are not concerned with for
                                                                                             41


              interoperability testing. The Formatter filters out any such irrelevant
              messages.


6.   Replacing point codes: All the files related to the test (such as the Expected Behavior,
     the Recorded Times of Test Actions, the Link Mapping File, and the Test Network
     Configuration) refer to network nodes in terms of their standard names described in
     section 0. To make the Actual Event Record consistent with these files, the Formatter
     replaces the point codes of the nodes that appear in the data with their names. For
     example if the point code of the node „STP_A‟ is „246-242-000‟, all instances of the
     point code „246-242-000‟ are replaced with „STP_A‟.
7.   Standardization of link names: As discussed in section 3.2.2.7, the data monitors have
     special names for the links in the network. The Formatter replaces these special
     names with the standard names of the links.
8.   Presenting the event: The Event Matcher has to demarcate individual events in the
     data. So, an easily identifiable string of special characters is inserted as both the first
     and the last line of every event to facilitate the demarcation of events. The following
     string   is   used   as   the    delimiter   for   all   events    in   the   data   files:
     “++++++++++++++++++++++++++++++++++++++++++”.
     After the event delimiter, the Formatter includes a line containing the match flag as
     described in section 5.1.5. The match flag is set to 0 in all events (indicating that the
     event has not yet been matched). The Specific Analyzer tries to find a message with
     the required parameters, whose match flag is 0 and changes the flag to 1, if the
     message is found.
              The first parameter that the Specific Analyzer reads is the time stamp of the
     event. Hence, the third line of the event consists of the synchronized and standardized
     time and also the original time stamp and the identifier of the file in which the event
     was found.

9.   Event Information: The Event Matcher needs to match only a few of the parameters
     contained in the unformatted data. The Formatter includes only these parameters in
                                                                                                 42


        the output, in one uniform format. The format of the events in the output is given in
        the Section 5.3.4.2.

10.     Data Integration: Each test will produce several data files from the various test
        elements. The events in the different files are interrelated, being mostly causally (and
        hence temporally) related or having the same cause. For example, when a link from
        an STP to a node is failed, the STP is expected to send Transfer Restricted (TFR)
        messages to its neighboring nodes, which results in those nodes responding with the
        signalling-route-set-test message (RSMs). These TFRs and RSMs will appear on
        different links and possibly in different data files. So, it is most convenient for the
        Specific Analyzer if all the events from the various data files are sorted
        chronologically and listed in a single file. The final task of the Formatter is to merge
        all the data files, sort the events and produce one data file that contains all the
        relevant events listed in chronological order. This is implemented by opening all the
        files at the same time, reading one message from each of them, finding out the event
        which occurred the earliest, performing tasks 2 to 9 as discussed above on each event,
        and writing the events as single lines, to a temporary file. A file whose events have
        been thus exhausted will be removed from the list of files that are being processed.
        The temporary file is then sorted using the system command sort to produce a
        temporally sorted file. This file has each event as a single line. Each line is expanded
        to produce the output file with events in the required format.

      The Formatter makes extensive use of Perl hash tables. The use of hash tables is
exemplified in the filtering stage of the program, where a hash table, with all relevant point
codes as indices and the corresponding node names as values, provides an elegant way of
checking if a point code is relevant to the test or not. If a line from one of the data files is
found to have a point code (by searching for a string pattern of the form „three digits‟-„three
digits‟-„three digits‟, e.g. 246-022-001), the hash table is indexed using the matched point
code. If the point code is relevant, it is a valid index of the hash table and the table will return
the corresponding node name, which when treated as a Boolean value is true in Perl. If it is
not relevant, the table will return null, which is a logical false. This comparison is done using
just one line of code. An alternative procedure would have been to build an array of strings
                                                                                            43


with all the relevant point codes and compare the matched point code with each of the array
values to determine if the point code is relevant, which involves a for loop.
5.3 Usage
5.3.1 Requirements
The Formatter is designed to run under the Unix or Microsoft Windows operating systems,
and requires that Perl (version 5.6.0 or higher) be installed. The Formatter uses the sort
program that is provided with the Unix or Windows operating systems. The structure of the
file system in which the Formatter is designed to operate is documented in appendix 1.
    The Formatter uses a library of symbol replacing functions (replace_lib.pm), the source
code for which is provided in Appendix B.


5.3.2 Command Usage
perl format testxx date
The testxx argument specifies the test whose Expected Behavior is to be translated and the
date argument is the date when the test was performed in the yyyymmmdd format. For
example if the tester wants to format the data for test 5.6 conducted on January 15 th of 2001,
the command to be used is:
perl Translator test56 2001jan15
The Formatter uses these two arguments to determine the directory and the names of the files
that it must process using the file system structure given in appendix 1.
5.3.3 Inputs
The Formatter takes as inputs the products of a test (the Recorded Times of Test Actions,
Clock Difference File, and monitored test data), and descriptions of the test configuration
(Link Mapping File, Pointcode Assignment File).
The Formatter takes these inputs and produces an output as shown in Figure 5.1 below:
                                                                                            44



                                 Test net. configuration


        NSTS link monitors
                                                           Link mapping file




       MGTS EMRs
                                                               Pointcode Assignment




  Record of Test Actions                                                Clock Differences
                                      Formatter




                                  Actual Event Record


                       Figure 5.1 Inputs and output of the data formatter

5.3.4 Output produced
The Formatter produces one flat text file as the output, called the Actual Event Record. The
location of this file is given in appendix 1. The Actual Event Record consists of the
following:


5.3.4.1 Monitored link names
The beginning of the AER lists the names of all the links that were monitored and for which
data is available. This information is derived from the LMF. The links are listed one per line,
with each line beginning with the word „link‟, and using the naming scheme as described in
section 0. To specify the direction in which the link was monitored, the node towards which
the messages flow accompanies the link name. As each link is bi-directional, each link name
could appear twice.
An excerpt from an AER is shown below:
Link Name                       Direction toward
link    D(STP_B)(STP_C)(0)              STP_B
link    D(STP_A)(STP_C)(0)              STP_C
                                                                                           45

link    C(STP_A)(STP_B)(0)              STP_A
link    C(STP_A)(STP_B)(1)              STP_A



5.3.4.2 Events
After the monitored link names, the AER then lists all events relevant to the test, temporally
sorted, from the input data files.
The first and the last line of each event will be the event delimiter (refer to function 8 in
Section 5.2). There are two kinds of events – messages and load measurements. The format
of the events is described below:

5.3.4.2.1 Messages
A message consists of five lines.
1) The first line is the event delimiter.
2) The second line is the match flag:
       MATCH_FLAG: 0
3) The third line contains the time of observation of the message by the monitor both in the
   seconds and milliseconds format and hrs:min:seconds format according the the original
   monitor clock. The latter allows the analyst to examine detailed monitor logs to obtain
   more information about events that the analysis highlights (e.g. unexpected events). It
   also contains the ’name’ of the data file from which the event was obtained. For example:
    35812.463           09:56:52.463            MACHINE1


4) The fourth line starts with the word „message’ and contains the parameters of the
   message in the following order, with each parameter separated by white space:
   message         link dir    OPC      DPC     msg_type    [p1]   [p2]

   link is the name of the link on which the message was observed going toward the node
   whose name is given by dir. OPC and DPC are the names of the origin and destination
   of the message. msg_type is the type of the message and p1 and p2 are the optional
   parameters of the message. The valid message types and the corresponding parameters
   are given in appendix 3.
5) The fifth line is the event delimiter.
An example message is shown here:
                                                                                              46

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MATCH_FLAG: 0
45595.107       12:39:55.107             MACHINE2
message         D(STP_A)(STP_D)(0)               STP_D STP_A STP_D TFA       SSP3
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++




5.3.4.2.2 Load Measurements
A load measurement consists of six lines and gives the load on a link in both directions. If
link is the name of the link, joining two nodes dir1 and dir2, the event in the AER will be as
follows:
1   The first line is the event delimiter.
2   The second line is the match flag, set to 0.
    MATCH_FLAG: 0
3   The third line is the time, as given in the description of the format of messages.
4   The fourth line starts with the word „load‟ and contains the total load, as a percentage
    (perc_load1) of the maximum load on the link given by the name link measured towards
    the node whose name is given by dir1 in the following order:
    load      link      dir1    perc_load1
5   The fifth line is similar to the fourth line, with dir2 instead of dir1 and the corresponding
    perc_load2 instead of perc_load1.

    load      link      dir2    perc_load2

6   The sixth line is the event delimiter.


An example load measurement is shown here:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MATCH_FLAG: 1
45619.782       12:40:19.782             NSTS2
load    D(STP_A)(STP_C)(1)              STP_A 0.05
load    D(STP_A)(STP_C)(1)              STP_C 25.23
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                                                          47


6 The Matching Process
As explained in the section 3.2, the Translator converts the Expected Behavior in SEBEL
into the Specific Analyzer, a Perl program that can be run on a computer. The Specific
Analyzer uses the functions in the Matching Library to perform the actual analysis. Section
6.1 explains the working of the Translator, Section 6.2 describes the Specific Analyzer and
Section 6.3 explains the functions in the Matching Library.


6.1 The Translator
6.1.1 Introduction
       Each test has an Expected Behavior associated with it, written in SEBEL, which
cannot be directly processed by a computer. The Translator converts the Expected Behavior
into a Perl program (the specific analyzer), which can then be run on a computer to match the
Expected Behavior against the actual test data.
       The relation between the Expected Behavior, the Translator and the Specific Analyzer
is comparable to that between a C source code, a C compiler and the resulting executable
program, which is pictorially shown below in Figure 6.1.


            SEBEL        Expected                              Source           C
                         Behavior                               Code



                         Translator                           Compiler         GCC




                         Specific                          Executable
             PERL                                                              a.out
                         Analyzer                           Program


Figure 6.1 Relationship between Expected Behaviour, Translator and Specific Analyzer

       Section 6.1.2 discusses the operation and implementation of the Translator and
Section 6.1.3 discusses the usage and external interfaces of the Translator.
                                                                                         48


6.1.2 Operation and Implementation
The Translator performs the following functions:
   Check the syntax of the Expected Behavior
   Add extra code
   Convert SEBEL functions into Matching Library functions
   Restructure the Expected Behavior Tree for a depth-first search
   Add timing information
These are described in the following sections.


6.1.2.1 Check the syntax of the Expected Behavior
Like any compiler, the Translator first checks the Expected Behavior for syntax errors. If
there are any errors detected, it shows them on the standard output (monitor) and the output
is not generated. After showing a maximum of 30 error messages, the Translator stops further
processing.
6.1.2.2 Add extra code
While the main role of the Translator is to compile SEBEL code into executable Perl code,
the Translator also makes writing code in SEBEL easier by adding low-level details to the
code. These are the following:
   Set definitions
   Times of test actions
   Using the Matching Library
   Commands to interface with the Actual Event Record
   Commands to generate results
   Obtain the list of monitored links
These are explained in detail in the following sections:

6.1.2.2.1 Set definitions
Sets are defined in the Expected Behavior to be used in the foreach loops (refer to Section
4.1.1.2). The sets consist of alphanumeric words, which must be placed within quotes in a
Perl program. The Translator adds quotes to all the elements in the sets defined in the
                                                                                             49


Expected Behavior and also adds the semicolon to each definition. Examples are shown
below.


In Expected Behavior:
@STPS_E=(STP_A, STP_B)
@STPS_W=(STP_C, STP_D)
@SSPS_E=(SSP_E1, SSP_E2, SSP_E3, SSP_E4, SSP_E5, SSP_E6, SCP_E1, SCP_E2)



In Specific Analyzer:
@STPS_E=("STP_A","STP_B");
@STPS_W=("STP_C","STP_D");
@SSPS_E=("SSP_E1","SSP_E2","SSP_E3","SSP_E4","SSP_E5","SSP_E6","SCP_E1","SCP_E2");



6.1.2.2.2 Times of test actions
The test actions in the Expected Behavior are accompanied by labels, which are used to
access the times at which the test actions were performed. The Expected Behavior uses labels
because the times of these test actions are not known when it is written. These times are
present in the Recorded times of Test Actions (RTA) file. The Translator sets the values of
these labels, which are scalar variables, to the times obtained from the RTA file. The RTA
contains times in the hours, minutes and seconds format. These times are converted to
seconds and milliseconds format in the Specific Analyzer. For example, 9:55:04 when
converted to seconds and milliseconds is 35764.
In RTA:
9:55:04     $beginning_of_test: test_begin()
9:56:44     $ta_fail{SSP_E1}: fail_link(A(246-253-000)(246-004-001))
10:02:00    $ta_fail{SSP_E2}: fail_link(A(246-253-000)(246-004-002))



In Specific Analyzer:
$beginning_of_test=35764;
$ta_fail{"SSP_E1"}=35804;
$ta_fail{"SSP_E2"}=36174;

The Translator also creates an array containing all the test action labels, which is used to set
the value of the variable $next_action_time discussed in section 6.1.2.5.
                                                                                                 50


6.1.2.2.3 Using the Matching Library
The Translator adds the following lines of code to the Specific Analyzer to enable it to use
the Matching Library functions:
use FindBin qw($Bin);
use lib "$Bin/../../../../BIN/analysis";
use matching_lib ();


6.1.2.2.4 Commands to interface with the Actual Event Record
The Translator adds code to interface with the Actual Event Record. This is done by adding a
command in the Specific Analyzer to produce a copy of the Actual Event Record, called the
Matched Event record and another command in the Specific Analyzer to open the Matched
Event Record using the file handle „DATA_FILE‟, which is the file handle name used by the
functions in the Matching Library.
        File handles are variables using which a program can access the contents of files. The
file handle has a value, which is the number of bytes of the file already read. This value is
also called the position of the file handle. The file handle values at certain locations in the file
are stored in scalar variables and the program can go back to those locations if needed using
these scalar varibales. For example, when an event causes two events, both the child events
should be searched starting immediately after the parent event. The position of the parent
event in the Matched Event Record is saved in a variable, so that after the first child event is
matched, the program can return to the position of the parent event and start searching for the
second child event. The following is the code that is added:
system ("copy","test52.aer", "test52.mer");
open(DATA_FILE,"+<test52.mer")||die "Could not open file:test52.mer";


6.1.2.2.5 Commands to generate results
The Specific Analyzer produces four files as intermediate results: the eXpanded eXpected
Behavior (XXB), the Missing Event List, the Hidden Event List and the Parameter
Observation List. These output files are described in Section 6.2.4. The Translator adds code
to the Specific Analyzer to open these files with the file handle names that the functions in the
Matching Library use to access the intermediate files. The names of the intermediate files
and their respective file handles are shown in the table below:
                                                                                              51


             Table 2: Names of intermediate files and their file handle names

Name of the file                               Name of the file handle
Missing Event List                             MEL_FILE
Unexpected Event List                          UEL_FILE
Hidden Event List                              HEL_FILE
Parameter Observation List                     POL_FILE
eXpected eXpected Behavior                     XXB_FILE


The code that is added is shown below:
open(MEL_FILE,">test52.mel");
open(UEL_FILE,">test52.uel");
open(HEL_FILE,">test52.hel");
open(POL_FILE,">test52.pol");
open(XXB_FILE,">test52.xxb");


6.1.2.2.6 Obtain the list of monitored links
The Translator adds a line of code that uses a function from the Matching Library to obtain
the list of all the links that were monitored from the Matched Event Record (MER). This list
is used by the event matching functions as explained in Section 6.3.4.
@monitored_links=&get_monitored_links();



6.1.2.3 Convert SEBEL functions into Matching Library functions
There are two types of events in the Expected Behavior description - messages and load
measurements. In SEBEL, messages are matched using the findmsg function and load
measurements are matched using the assert_load function. There is also a pseudo-event used
to record the observed timer values, which is implemented using the waitfor function. These
three functions together with the test actions as described in the section 2.2, are the functions
supported by SEBEL.
The next four subsections describe the conversion into Matching Library functions of the
findmsg and assert_load events, the waitfor pseudo-event, and finally the test actions.
                                                                                           52


6.1.2.3.1 The findmsg and assert_load functions
Perl requires that all scalar variables be named starting with a $ sign, all arrays be named
starting with an @ sign and all functions be named with an & sign. The Translator appends
an & in front of all test actions, findmsg, and assert_load functions. Each of these functions
has a line number in the Expected Behavior file. The Translator puts this number as the first
argument to each of these functions. For findmsg and assert_load, all the arguments of the
SEBEL function are then added. Double quotes are put around all arguments that are not pure
numbers. A semicolon is added at the end of the line since all Perl statements end with
semicolons. An example for each function is shown below:
   1. findmsg:
   In Expected Behavior:
 182.        findmsg(C(STP_A)(STP_B), STP_B, STP_D, STP_B, RCP, SSPS_2)

   After Conversion:
&findmsg(182,"C(STP_A)(STP_B)","STP_B","STP_D","STP_B","RCP","SSPS_2");



   2. assert_load:
   In Expected Behavior:
115. assert_load(D(STP_A)(STP_D), STP_A, 20)

   After Conversion:
&assert_load(115,"D(STP_A)(STP_D)","STP_A",20);


6.1.2.3.2 The waitfor function
In the Expected Behavior, a waitfor function always causes other events (functions). The
Translator combines the waitfor function and the function that it causes as a single
write_timer function. The first argument of the write_timer function is the line number of the
waitfor, the following arguments are the arguments of the waitfor – the time when the timer
is started ($waitfor_time[$wait_hier], which will be discussed in Section 6.1.2.5.1.4), the
name of the timer and the name of the particular STP, the name of the function that the
waitfor causes and all the arguments of that function. Double quotes are put around all
arguments that are not pure numbers. An „&‟ sign is added in the beginning and a semicolon
is added at the end of the line. An example is shown below:
In Expected Behavior:
                                                                                             53

68. waitfor(T11, STP_B) causes 69
69. findmsg(C(STP_A)(STP_B), STP_A, STP_B, STP_A, TFR, STP_D)



After Conversion:
&write_timer(68,$waitfor_time[0],"T11","STP_B","findmsg",72,
                  "C(STP_A)(STP_B)","STP_A","STP_B","STP_A","TFR","STP_D");




6.1.2.3.3 SEBEL Test actions
All test actions in the Expected Behavior are converted into the same function called
test_action. For a test action, the complete SEBEL line in the Expected Behavior is added as
the second argument to the test_action function. A semicolon is added at the end of the line
since all Perl statements end with semicolons. An example is shown below:
In Expected Behavior:
51.fail_link(D(STP_B)(STP_D)(0))
After Conversion:
&test_action(51,"fail_link(D(STP_B)(STP_D)(0))");



6.1.2.4 Restructure the Expected Behavior Tree for a depth-first search
The Expected Behavior is a list of events (parents) causing other events (children). So, the
Expected Behavior is the description of a tree. But the events in the Expected Behavior are
put together using the causes construct and hence are not listed in any fixed tree traversal
order. The Translator orders all the events in a depth-first tree traversal order. The causes
relation is converted into an „if’ condition. For example, if the tree described by the Expected
Behavior is the one shown in Figure 6., with the nodes in the tree standing for events, the
Translator orders the nodes as shown in the picture to the right.
                                                                                                         54


                 Expected Behavior Tree                  Ordering by the Translator
                                                                if ( 1 ){
                                                                            if ( 2 ){
                               1
                                                                                        if( 5 ){
                                                                                                   10;
                                                                                                   11;
                                                                                                   12;
                      2        3         4                                              }
                                                                                        6;
                                                                                        7;
                                                                            }
            5         6       7          8        9                         3;
                                                                            if ( 4 ){
                                                                                        8;
                                                                                        9;
  10        11       12                                                     }
                                                                }



         Figure 6.2: Ordering of the Expected Behaviour tree by the Translator


6.1.2.5 Add timing information
       The event matching functions search for an event from the time of the event that
caused this event until the time of the next test action. However, this timing information is
not explicitly stated in the EB. The next step for the Translator is to supply this information
in the calls to the event matching functions findmsg and assert_load.
        The time range is given in the Specific Analyzer using the two scalar variables $time
and $next_action_time. $time is usually the time of the last expected event found in the actual
data. Unless in a while loop, $next_action_time is the time of the next test action, which is
obtained from the Recorded times of Test Actions. In a while loop, the value of
$next_action_time is set to the limit specified in the while loop. The functions in the
Matching Library try to find expected events in the actual data in the time interval starting at
$time and ending at $next_action_time. To speed up the searching process, it is necessary to
move the file pointer of the Matched Event Record (DATA_FILE) to follow the variable
$time. So, the value of the file pointer „DATA_FILE‟ is constantly updated so that it always
points to the last event in the Matched Event Record appearing before $time. The handling of
the timing information is explained in more detail in the following sections.
                                                                                           55


       Events in the Expected Behavior are classified into simple events and compound
events. A simple event is that which is only one event. Test actions, messages, load
measurements and timer observations are simple events. For example, a findmsg event is
used to match one particular message. By contrast, compound events are those that consist of
multiple events. For example, if an event causes multiple events, the parent event can be
considered to be a compound event consisting of all the events in the sub-tree rooted at his
event. In Figure 6. shown below, test action a causes the compound event 1, which consists
of seven simple events 1, 4, 5, 6, 9, 10, and 11.



                                                            Test action a




                                          1             2                   3




                             4            5         6                       7     8




               9            10           11



                      Figure 6.3 Simple events and compound events

There are three types of compound events, an event with the causes construct as explained
above, foreach loops and while loops. The addition of timing information for the simple
events is described in section 6.1.2.5.1 and the same for the compound events is described in
section 6.1.2.5.2.



6.1.2.5.1 Simple Events
Test actions, the findmsg and assert_load functions and the waitfor pseudo-event are the
simple events. The addition of timing information for these is described below:

6.1.2.5.1.1 Test Actions
                                                                                              56


The test actions are the only events whose times of occurrence are known before the analysis.
Each test action in the Expected Behavior has a label attached to it, which represents the time
of execution of the test action. The Translator obtains the actual times of execution of the test
actions from the Recorded Times of Test Actions. The Specific Analyzer has an array called
@test_action_labels, which initially contains the time ordered list of all the test action time
labels. When a test action is encountered in the Expected Behavior, the following steps are
performed:
1. The first element in the array @test_action_labels is removed.
2. The variable $time is set to the value of the removed element.
3. The file handle „DATA_FILE‟ is moved to the closest event that occurred before $time.
4. The variable $next_action_time is set to the value of the new first element of the array
   @test_action_labels.
An example is shown below:
In Expected Behavior:
1. $beginning_of_test: test_begin()
In the Specific Analyzer:
&test_action(1,"test_begin()");
shift @test_action_labels;
$time=$beginning_of_test;
&seek_fp($time);
$next_action_time=$test_action_labels[0];


&seek_fp($time), is a function in the Matching Library, which moves the file pointer
„DATA_FILE‟ to $time.

6.1.2.5.1.2 findmsg

The specific analyzer does not need any additional timing information for the findmsg
function. The correct values of $time and $next_action_time would already have been set. In
the Matching Library function findmsg, before the search is started, the values of the variable
$time and the file pointer DATA_FILE are stored in private variables of the function. The
Matched Event Record is then searched sequentially for the message. Both $time and
                                                                                         57


DATA_FILE change with each message read from the Matched Event Record during the
search. If the message is successfully found, $time and DATA_FILE are set to the time and
position of the matched message in the Matched Event Record. If the message is not found in
the required time range, then $time and DATA_FILE are set to the old values saved in the
private variables. An example is shown below:
In Expected Behavior:
 182.           findmsg(C(STP_A)(STP_B), STP_B, STP_D, STP_B, RCP, SSPS_2)

In Specific Analyzer:
&findmsg(182,"C(STP_A)(STP_B)","STP_B","STP_D","STP_B","RCP","SSPS_2");


6.1.2.5.1.3 assert_load

The actions performed in the Specific Analyzer for assert_load are as follows:
1. Before the search is made, the values of $time and DATA_FILE are stored in temporary
   variables.
2. After the search is complete, the values of $time and DATA_FILE are set back to the old
   values stored in the temporary variables.
An example is shown below:
In Expected Behavior:
5. assert_load(D(STP_A)(STP_C), STP_C, 10)

In the Specific Analyzer:
$pre_load_time=$time;
$pre_load_fp= tell DATA_FILE;
&assert_load(5,"D(STP_A)(STP_C)","STP_C",10);
$time=$pre_load_time;
seek DATA_FILE,$pre_load_fp,0;


6.1.2.5.1.4 Waitfor

A waitfor pseudo-event causes one or more events, each of which can cause other waitfor
pseudo-events. The level of this hierarchy is stored in the variable $wait_hier in the
Translator. For example, if a waitfor causes an event that causes another waitfor, the first
waitfor will be associated with a $wait_hier value of 0 and the second waitfor with a
$wait_hier value of 1. The actions performed for waitfor are as follows:
1. The value of $wait_hier is increased by 1 in the Translator.
                                                                                            58


2. The time of the event that caused the waitfor is saved in the array element
    $waitfor_time[$wait_hier].
3. The events caused by the waitfor are converted to write_timer functions.
4. The value of $wait_hier is decreased by 1.
An example is shown below:
In Expected Behavior:
68. waitfor(T11, STP_B) causes 69
69. findmsg(C(STP_A)(STP_B), STP_A, STP_B, STP_A, TFR, STP_D)

In Specific Analyzer:
$waitfor_time[0]=$time;
&write_timer(68,$waitfor_time[0],"T11","STP_B","findmsg",69,
                  "C(STP_A)(STP_B)","STP_A","STP_B","STP_A","TFR","STP_D");




6.1.2.5.2 Compound Events
The causes construct, the foreach and the while loops are the compound events in SEBEL.
The addition of timing information for these by the Translator is described below:

6.1.2.5.2.1 The causes construct

When an event causes other events, the child events could occur anytime between the
occurrence of the parent event and the next test action. So, in the Specific Analyzer, the time
of occurrence of the parent event and the corresponding value of the file handle DATA_FILE
are saved and before each of the child events, the values of the variables $time and
DATA_FILE are set to the saved values. Since a depth-first tree traversal is to be carried out
in the Specific Analyzer, the times and the positions of the file handle DATA_FILE need to be
saved to return to later, at various depths in the tree. For example in Figure 6. shown below,
the order of traversal will be: 1, 4, 9, 10, 11, 5, 6, 2, 3, 7 and 8. This means that after
matching event 9, event 10 is to be matched between the time t4 and the time of the next test
action. Similarly after matching event 10, events 5 and 6 are to be matched between the time
t1 and the time of the next test action.
                                                                                                59


       ta0
                                                                 Test action a



      t1
                                           1                 2                   3



      t4
                           4              5              6                       7        8




             9            10              11

                 Figure 6.4 Depth first tree traversal and timing information

The depth of the tree is saved in a variable $tree_hier in the Translator, starting with a value
of zero at the root (test action) of the tree. In the figure above, the value of $tree_hier will be
0 at the test action; 1 at events 1,2 and 3; 2 at events 4, 5, 6, 7 and 8 and so on. The variables
$parent_time[$tree_hier] and $parent_fp[$tree_hier] hold the values of the time and the
position of the file handle DATA_FILE respectively at a depth $tree_hier. After matching
one child of a parent event, the values of $time and DATA_FILE are returned to the values
saved in the variables $parent_time[$tree_hier] and $parent_fp[$tree_hier]. An example is
shown below:
In Expected Behavior:
51. $td4_0_fail: fail_link(D(STP_B)(STP_D)(0)) causes 52
52. findmsg(D(STP_B)(STP_D)(1),STP_D,STP_B,STP_D,COO,
                                                    D(STP_B)(STP_D)(0)) causes 53
53. findmsg(D(STP_B)(STP_D)(1), STP_B, STP_D, STP_B, COA,
                                                    D(STP_B)(STP_D)(0))

In Specific Analyzer:
if (&test_action(51,"fail_link(D(STP_B)(STP_D)(0))")) {
       $parent=51;
       $new_action_time=shift @test_action_labels;
       $next_action_time=$test_action_labels[0];
                                                                                          60

        $time=$td4_0_fail;
        &seek_fp($time);
        $old_action_time=$time;
        $parent_time[0]=$time;
        $parent_fp[0]=tell DATA_FILE;
        $time=$parent_time[0];
        seek DATA_FILE,$parent_fp[0],0;
        if(&findmsg(52,"D(STP_B)(STP_D)(1)","STP_D","STP_B","STP_D","COO","D
(STP_B)(STP_D)(0)")) {
          $parent=52;
          $parent_time[1]=$time;
          $parent_fp[1]=tell DATA_FILE;
          $time=$parent_time[1];
          seek DATA_FILE,$parent_fp[1],0;
        &findmsg(53,"D(STP_B)(STP_D)(1)","STP_B","STP_D","STP_B","COA","D(ST
P_B)(STP_D)(0)");
}
}




6.1.2.5.2.2 Foreach loop

A line in the Expected Behavior inside a foreach loop is actually multiple events caused by
the same event. This is similar to the causes construct explained above. For example in
Figure 6. shown below, the line in the foreach loop is repeated thrice as shown in the figure
on the right.
                                                                                                        61




                                                             x       y      z
    foreach $s (@list) { $s }

    @list = (x,y,z);
                                                          x is the „real‟ node in the tree. This is
    $s takes values x,y and z in the loop.
                                                         the same event as the event to the left with
     $s is the pseudo node in the for loop. This
                                                         parameter $s=„x‟.
    is an event with parameter $s.


                                Figure 6.5 Expansion of the foreach loop

Hence, the timing information added is similar to that discussed in the previous section. An
example is shown below:
In Expected Behavior:
229. foreach $s (@SSPS_E) {
230.              findmsg(A(STP_B)($s), $s, STP_B, $s, TCP, SSPS_2)
231. }

In Specific Analyzer:
$parent_time[1]=$time;
$parent_fp[1]=tell DATA_FILE;
foreach $s (@SSPS_E) {
           &findmsg(230,"A(STP_B)($s)","$s","STP_B","$s","TCP","SSPS_2");
           $time=$parent_time[1];
           seek DATA_FILE,$parent_fp[1],0;
}


6.1.2.5.2.3 While loop

An event in the while loop is a string of events, whose timing details are taken care of by the
functions in the Matching Library. No special information needs to be added to the specific
analyzer regarding the event inside the while loop. Since the event matching functions search
for an event from the time of the event that caused this event until the time of the next test
action, and the while loop specifies its own upper time limit, the value of the variable
$next_action_time is temporarily stored in another variable, $temp_action_time and the value
                                                                                            62


of the variable $next_action_time is set to the limit specified in the while loop. The variable
$next_action_time is returned to its original value after getting out of the while loop. The
values of $time and DATA_FILE are saved to be returned to after getting out of the while
loop. The variables $while_flag and $find_flag are used in the Matching Library to keep a
count of the number of messages found corresponding to the message in the while loop. The
way the while loop is expanded by the Specific Analyzer is shown in Figure 6..



                                                        Time



       while ($time < $end)                                 *
              {*}                                               *
                                                                    *
                                                     $end




                              Figure 6.6 Expansion of the while loop

An example is shown below:
In Expected Behavior:
192. while($time<$td3_1_restore) {
193.          waitfor(T10, STP_D, $td3_1_restore) causes 194
194.          findmsg(C(STP_C)(STP_D), STP_C, STP_D, STP_C, RSR, STP_B)
195. }

In Specific Analyzer:
$temp_action_time=$next_action_time;
$next_action_time=$td3_1_restore;
$pre_while_time=$time;
$pre_while_fp=tell DATA_FILE;
$while_flag=1;
$find_flag=0;
while($time<$td3_1_restore) {
         $waitfor_time[1]=$time;
                                                                                          63

       &write_timer(193,$waitfor_time[1],"T10","STP_D","findmsg",194,"C(STP
_C)(STP_D)","STP_C","STP_D","STP_C","RSR","STP_B");
}
$next_action_time=$temp_action_time;
$time=$pre_while_time;
seek DATA_FILE,$pre_while_fp,0;
$while_flag=0;



6.1.3 Usage
6.1.3.1 Requirements
The requirements are the same as for the Formatter, given in section 5.3.1.
6.1.3.2 Command Usage
perl Translator testxx date
Refer to Section 5.3.2 for more details.
6.1.3.3 Inputs
Apart from the Expected Behavior, the Translator takes as inputs the Recorded Times of Test
Actions, and descriptions of the test configuration (Pointcode Assignment and Test Network
Configuration files). The Recorded Times of Test Actions is used to provide the timing
information and the test configurations files are used to verify the links and nodes that the
Expected Behavior uses.
The Translator takes these inputs and produces an output as shown in Figure 6..
                                                                                          64


                                                      Expected Behavior
                     Pointcode Assignment                 of a test




               Test Network.                                     Recorded Times of Test
               configuration                                            Actions




                                            Translator




                                              Specific
                                            Analyzer for
                                              the test


                         Figure 6.7 Inputs and output of the Translator



6.1.3.4 Output produced
The Translator produces one text file as the output, called the Specific Analyzer. The naming
scheme and the location of the Specific Analyzer are given by the file system structure in
appendix 1. The Specific Analyzer is a Perl program, which takes the Actual Event Record as
its input and produces intermediate results as explained in section 6.2.
6.2 Specific Analyzer
The Specific Analyzer is the program that actually matches the Expected Behavior with the
real data for a particular test run using the functions in the Matching Library and produces
various intermediate output files.
For details about the implementation and internal operation of the Specific Analyzer, the
reader should consult the sections about the Translator (section 6.1) and the Matching
Library (section 6.3).
6.2.1 Requirements
The requirements are the same as for the Formatter, given in section 5.3.1.
                                                                                            65


6.2.2 Usage
perl testxx.anz
Refer to Section 5.3.2 for more details.

6.2.3 Inputs
The Translator produces the Specific Analyzer from the Expected Behavior of a test for a
particular run of the test. The Specific Analyzer takes the Actual Event Record (Section
5.3.4) for the same run of the test as input, and produces five output files as shown in Figure
6.8:



                                  Actual Event Record




                                      Specific
                                    Analyzer for
                                      the test
                                                                    Parameter Observation
 Mached Event Record                                                        List




                                                                 Hidden Event List
          Expanded Expected
              Behavior

                                   Missing Event List


                   Figure 6.8 Inputs and output of the Specific Analyzer

6.2.4 Outputs produced
The Specific Analyzer produces output files which give information about whether the
expected events were found, missing or hidden in the actual data, any unexpected events in
the actual data, details about load measurements and observed values of timers of the STPs
involved in the particular test. The output files are described below:
                                                                                               66


6.2.4.1 Matched Event Record
The Matched Event Record is a copy of the Actual Event Record (AER), with the only
difference being that the MATCH_FLAG fields of each event, which are all set to 0 in the
Actual Event Record, are now set to 0,1 or a „*‟. These different values are used after the EB
has been matched against the Actual Event Record to determine which events were
unmatched ('0'), and of the matched events, which were matched with wildcards ('*') and
which were not ('1'). These values are set based on the criteria given below:
1. Match flag set to 1:
   When a message in the AER has matched an expected message, which has definite values
      for all its parameters, the match flag is set to 1.
2. Match flag set to ‘*’:
   When a message in the AER has matched an expected message, which has at least one
      wildcard parameter, the match flag is set to „*‟.
3. Match flag set to 0:
   a. Load Measurements
      The Actual Event Record contains the load measurements of all the monitored links
          at regular intervals. The Expected Behavior specifies only a few load measurements
          to be matched. This means that not all load measurements in the Matched Event
          Record are matched against the expected loads and updated to reflect whether they
          matched the expected loads or not. Hence, all load measurements in the MER have a
          match flag set to 0. The information regarding the matching of load measurements
          present in the Expected Behavior is written to the Parameter Observation List.
      b. Messages
         All the messages that were not present in the Expected Behavior will have their match
          flags set to 0. This means that all messages that have their match flags set to 0 in the
          MER are unexpected messages.


6.2.4.2 Expanded Expected Behavior
During analysis, the Expanded Behavior (EXB) is expanded so that each item in a foreach
loop is repeated once per iteration of that loop. For example, if a TFR message was expected
for each of the 5 SSPs in set @set_1 connected to a STP, and this was expressed as a single
line in a foreach loop:
19.           foreach $t (@set_1) {
                                                                                             67

20.                findmsg(A(STP_A)($t), $t, STP_A, $t, TFR, SSP_E1)
21.          }



The line numbered 20 is then expanded to 5 lines, each of which states that a TFR was
expected for a specific SSP.
20. findmsg(A(STP_A)(SSP_E2),SSP_E2,STP_A,SSP_E2,TFR,SSP_E1)
20. findmsg(A(STP_A)(SSP_E3),SSP_E3,STP_A,SSP_E3,TFR,SSP_E1)
20. findmsg(A(STP_A)(SSP_E4),SSP_E4,STP_A,SSP_E4,TFR,SSP_E1)
20. findmsg(A(STP_A)(SSP_E5),SSP_E5,STP_A,SSP_E5,TFR,SSP_E1)
20. findmsg(A(STP_A)(SSP_E6),SSP_E6,STP_A,SSP_E6,TFR,SSP_E1)



Note that if an expected event is in a while loop, the number of times it is expected to be seen
is not known in advance. Hence, an event in a while loop is written only once into the
Expanded Expected Behavior along with the number of times it was observed.
All such expanded events and the test actions in the EXB are written to the Expanded
Expected Behavior (XXB) file, in the order in which they are encountered by the specific
analyzer. If a message is inside a while loop, the word „WHILE: ‟ is appended next to the
event, along with the number of times the message was seen in the AER in the specified
period of time.
         After matching with the actual data, there are 3 different outcomes for a message and
one more for a load measurement. All four outcomes are listed below; the first three are valid
for messages and load measurements and the fourth one is valid for loads only.
1     Hidden:
      If the link or link-set on which the event was expected was not monitored, then the word
      „HIDDEN‟ is appended to the event in the XXB.
2     Found:
      If the event in the Expected Behavior was matched in the actual data, then the word
      „FOUND‟ is appended to the event in the XXB.
3     Not found:
      If the event was not matched in the actual data, then the phrase „NOT FOUND‟ is
      appended to the event in the XXB.
4     Load measurement unavailable:
                                                                                            68


   Sometimes, the load measurement for a particular link is not available in the required
   period of time even though the link was monitored. In this case, the phrase „NO
   MEASUREMENT‟ is appended to the event in the XXB.
Excerpts from an EXB and the corresponding XXB for one particular run of the test are
shown below:
EXB:
143. foreach $b (@SP_AB) {
144. findmsg(A(STP_A)($b), $b, STP_A, $b, TFR, STP_C)
145. }
146. findmsg(C(STP_A)(STP_B), STP_B, STP_A, STP_B, TFR, STP_C) causes 147
147. while($time<$ta_restore) {
148. waitfor(T10, STP_B, $ta_restore) causes 149
149. findmsg(C(STP_B)(STP_A), STP_A, STP_B, STP_A, RSR, STP_C)
150. }
151. assert_load(D(STP_A)(STP_C), STP_C, 0)
152. assert_load(D(STP_A)(STP_C), STP_A, 0)



XXB:
144. findmsg(A(STP_A)(SSP5),SSP5,STP_A,SSP5,TFR,STP_C,)HIDDEN
144. findmsg(A(STP_A)(SSP6),SSP6,STP_A,SSP6,TFR,STP_C,)HIDDEN
144. findmsg(A(STP_A)(SCP1),SCP1,STP_A,SCP1,TFR,STP_C,)HIDDEN
146. findmsg(C(STP_A)(STP_B),STP_B,STP_A,STP_B,TFR,STP_C,)NOT FOUND
149. findmsg(C(STP_B)(STP_A),STP_A,STP_B,STP_A,RSR,STP_C,)WHILE:0 NOT FOUND
151. assert_load(D(STP_A)(STP_C)(0),STP_C,0)FOUND
151. assert_load(D(STP_A)(STP_C)(1),STP_C,0)FOUND
152. assert_load(D(STP_A)(STP_C)(0),STP_A,0)FOUND
152. assert_load(D(STP_A)(STP_C)(1),STP_A,0)FOUND



6.2.4.3 Missing Event List
The Missing Event List (MEL) lists all the test actions with their corresponding times of
occurrence and any events in the Expected Behavior that were not matched in the actual data,
called missing events. The missing events are listed between the test action that caused them
(directly or indirectly) in the EXB and the next test action. The missing event in the MEL is a
replica of a message (findmsg function) or a load measurement (assert_load function) in the
EXB, with all the parameters and the line number. Next to the missing event are printed the
word „parent:‟ and the line number of the event that caused the event in the EXB. The line
                                                                                          69


number of the parent event is printed to help a tester to trace the missing events. A missing
event whose parent event also is missing is less serious than a missing event whose parent
event was matched. The MEL that contains the missing events for the example EXB given in
the previous section is shown below:
Test Action - 119 fail_link(D(STP_A)(STP_C)) TIME: 59580
120. findmsg(D(STP_A)(STP_C)(1),STP_C,STP_A,STP_C,COO,D(STP_A)(STP_C)(0))   parent: 119
141. findmsg(D(STP_C)(STP_B),STP_C,STP_B,STP_C,RSP,STP_A,)   parent: 138
146. findmsg(C(STP_A)(STP_B),STP_B,STP_A,STP_B,TFR,STP_C,)   parent: 138
149. findmsg(C(STP_B)(STP_A),STP_A,STP_B,STP_A,RSR,STP_C,)   parent: 146
154. findmsg(D(STP_A)(STP_D),STP_A,STP_D,STP_A,RSP,STP_C,)   parent: 151
Test Action - 166 fail_link(D(STP_B)(STP_C)) TIME: 59799




6.2.4.4 Hidden Event List
Both messages and load measurements are to be observed on a particular link or a link-set.
Sometimes the link(s) might not be monitored and it is not possible to find out whether the
event actually occurred or not. The events for which the required link(s) were not monitored
are termed hidden events and all such hidden events are listed in the Hidden Event List
(HEL), suitably positioned between test actions as per the description given in the previous
section. The HEL for the example given in the previous section is shown below:
Test Action - 119 fail_link(D(STP_A)(STP_C)) TIME: 59580
144. findmsg(A(STP_A)(SSP5),SSP5,STP_A,SSP5,TFR,STP_C,)
144. findmsg(A(STP_A)(SSP6),SSP6,STP_A,SSP6,TFR,STP_C,)
144. findmsg(A(STP_A)(SCP1),SCP1,STP_A,SCP1,TFR,STP_C,)
164. assert_load(C(STP_A)(STP_B)(1),STP_A,0)
165. assert_load(C(STP_A)(STP_B)(1),STP_A,0)
Test Action - 166 fail_link(D(STP_B)(STP_C)) TIME: 59799




6.2.4.5 Parameter Observation List
The Parameter Observation List (POL) is used to record two types of observations - load
measurements and timer observations.

6.2.4.5.1 Load Measurements
The Matching Library function assert_load finds all the load measurements in the required
time interval on the given link. The exact procedure of matching the expected load in the
Actual Event Record is given in the section 6.3.
                                                                                            70


In the EXB, sometimes the link on which the load is to be measured is given as a link-set i.e.,
two links. For example:
5. assert_load(D(STP_A)(STP_C), STP_C, 10)

But there are two links in the link-set – D(STP_A)(STP_C)(0) and D(STP_A)(STP_C)(1).
The assert_load function in the Matching Library will call itself twice – once for each link,
and the POL will contain measurements for both the links. The expected load measurement
in the example above is said to be matched if the loads on both the links match the loads in
the Actual Event Record.
POL:
FOUND LOAD - 5 D(STP_A)(STP_C)(0) STP_C 10 ACTUAL:9.89 TIME:35771.916
FOUND LOAD - 5 D(STP_A)(STP_C)(0) STP_C 10 ACTUAL:9.47 TIME:35801.922
FOUND LOAD - 5 D(STP_A)(STP_C)(1) STP_C 10 ACTUAL:11.51 TIME:35771.925
FOUND LOAD - 5 D(STP_A)(STP_C)(1) STP_C 10 ACTUAL:11.22 TIME:35801.931



As explained in section 6.2.4.2, the matching an expected load has four possible outcomes.
The information written into the Parameter Observation List for each of these four outcomes
is given below:
1   Load Matched:
    If at least one such measurement matches the expected load, each measurement will
    contain the phrase „FOUND LOAD‟ in front. Each measurement will also have the line
    number in the EXB and the parameters in the assert_load function. This will be followed
    by the actual load measurement from the data and the time of measurement of the load.
    Example:
    EXB:
    10. assert_load(D(STP_B)(STP_C)(0), STP_B, 10)

    POL:
    FOUND LOAD - 10 D(STP_B)(STP_C)(0) STP_B 10 ACTUAL:8.91 TIME:35771.903
    FOUND LOAD - 10 D(STP_B)(STP_C)(0) STP_B 10 ACTUAL:11.52 TIME:35801.909

2   Load not matched:
    If none of the load measurements match then each measurement will contain the phrase
    „NOT FOUND LOAD‟ in front. The rest of the line is the same as for the case above.
    Example:


    POL:
                                                                                                71

    NOT FOUND LOAD - 222 C(STP_A)(STP_B)(1) STP_A 20 ACTUAL:24.24 TIME:37813.121
    NOT FOUND LOAD - 222 C(STP_A)(STP_B)(1) STP_A 20 ACTUAL:24.86 TIME:37843.139
    NOT FOUND LOAD - 222 C(STP_A)(STP_B)(1) STP_A 20 ACTUAL:25.38 TIME:37873.149
    NOT FOUND LOAD - 222 C(STP_A)(STP_B)(1) STP_A 20 ACTUAL:25.36 TIME:37903.159



3   No load measurements in the time interval:
    If there are no load measurements in the required time interval then the phrase „LOAD
    MEASUREMENT NOT FOUND‟ is appended in front and the lower and upper limits of
    the interval are printed in the end.
    Ex:
    LOAD MEASUREMENT NOT FOUND : 398, D(STP_A)(STP_C)(0),BEGIN TIME:39182, END TIME:39317.605




4   Hidden load measurements:
    If the link was not monitored, the EB line will be written to the HEL.



6.2.4.5.2 Timer Observations:
Writing the timer observation involves finding a message. A waitfor can cause more than one
message. An observation is written in the POL for each such message. Again, as explained in
section 6.2.4.2, there are three possible outcomes for matching a message. The timer
observation written into the POL for each of these three outcomes and for the special case
when the message in a while loop is described below:
1   Message found:
    If the message is found, the timer value is calculated and is written as one line in the
    POL. The first parameter written is the line number of the waitfor line in the EXB. The
    second parameter is the name of the timer, the third is the name of the STP and the final
    parameter is the observed timer value in seconds.
    EXB:
    82. waitfor(T11, STP_D, $td4_1_restore) causes 86
    86. findmsg(C(STP_C)(STP_D), STP_C, STP_D, STP_C, TFR, STP_B) causes 87



    POL:
    82    T11   STP_D    35.289



    waitfor causing multiple messages:
                                                                                             72


    EXB:
    18.         waitfor(T11, STP_A, $ta_restore{$s}) causes 19, 22
    19.         foreach $t (@set_1) {
    20.               findmsg(A(STP_A)($t), $t, STP_A, $t, TFR, $s)
    21.         }
    22.         foreach $t (@set_2) {
    23.               findmsg(C(STP_A)(STP_B), STP_B, STP_A, $t, TFR, $s) causes 24
    24.               findmsg(A(STP_B)($t), $t, STP_A, $t, TFR, $s)
    25.         }



    POL:
    18    T11       STP_A   8.533
    18    T11       STP_A   8.535
    18    T11       STP_A   8.538
    18    T11       STP_A   8.540
    18    T11       STP_A   8.541
    18    T11       STP_A   8.544



2   Message not found:
    If the message is not found, no information is written to the POL.
3   Message hidden:
    The phrase „DATA HIDDEN‟ is written followed by the line number, timer name and the
    STP name.
    POL:
    68 T11 STP_B DATA HIDDEN
    68 T11 STP_B DATA HIDDEN
    68 T11 STP_B DATA HIDDEN



4   Message in a while loop:
    If the waitfor appears in a while loop, it always causes only one event. The word „while‟
    is written at the end of the line, followed by the beginning time and the ending time of the
    while loop for each occurrence of the message.
    EXB:
    192. while($time<$td3_1_restore) {
    193.        waitfor(T10, STP_D, $td3_1_restore) causes 194
    194.        findmsg(C(STP_C)(STP_D), STP_C, STP_D, STP_C, RSR, STP_B)
    195. }



    POL:
                                                                                            73

   193 T10     STP_D   81.803 while 39596 37865.803
   193 T10     STP_D   60.005 while 39596 37925.808
   193 T10     STP_D   60.000 while 39596 37985.808




6.3 Matching Library
The Matching Library contains the functions that are used by the Specific Analyzer to match
expected events against the actual data and to write the results of this matching to the output
files. Sections 6.3.1 and 6.3.2 discuss the requirements and the interface with the Specific
Analyzer respectively, Section 6.3.3 describes the matching procedure and Section 6.3.4
explains the various functions in the Matching Library in detail.


6.3.1 Requirements
The requirements are the same as for the formatter, given in section 5.3.1.

6.3.2 Interface with the Specific Analyzer
As described in Section 6.2, the Specific Analyzer opens the input and output files using file
handles that are used in the Matching Library functions.


6.3.3 The matching procedure
The outline of the matching procedure used in the functions findmsg and assert_load is
described below. The Specific Analyzer supplies the type of event, the link on which it is
expected to appear and the parameters to be matched, and also the times t1 and t2 within
which the event is to be found in the AER.
                                                                                           74


                             Find Event on link, params, [t1,t2]


                                   YES           Was the link         NO
                                                 monitored?                   Hidden
                                                                              Event
                                                                               List
                       Search for event in         Timers        Parameter
                                                   or load      Observation
                        the time period
                                                                    List




                                                                 Missing
Set Match      YES
                      Message?
                                  YES      Event        NO       Event
Flag to 1                                 Found?
                                                                  List


                                                                              Unexpected
           Matched               Find all messages with                         Event
            Event                   Match Flag = 0                               List
           Record
                                               Unexpected Event Finder

                         Figure 6.9 The matching procedure

The procedure for matching a message or a load measurement against the AER and
producing the output files is explained below:
1. Check if the link on which the event is to be matched was monitored. If it was not
   monitored, then write the event to the Hidden Event List. If it was monitored, proceed
   to step two.
2. Search for the event in the Matched Event Record, if the event is not found, then
   write the event to the Missing Event List. If the event is a message and is found, set
   the match flag of the message in the Matched Event Record to 1.
After all the events in the Specific Analyzer are matched, the Event Summarizer
generates the Unexpected Event List, which contains all the messages in the Matched
Event Record that have their match flags still set to 0.
                                                                                           75


6.3.4 The Functions
The following sections describe the functions in the Matching Library. The task performed
by each function is used as the section title and the name of the function is given in
parenthesis.


6.3.4.1 Obtain the list of all monitored links (get_monitored_links)
As explained in section 5.3.4.1, the Actual Event Record has a list of the links that were
monitored during the test. To aid in the matching process as described in section 6.3.3, the
Specific Analyzer accesses this list by using the function get_monitored_links. The function
takes no arguments and returns an array, named @monitored_links to the Specific Analyzer,
containing the names of the links and the directions in which they were monitored.
USAGE: @monitored_links=get_monitored_links();


6.3.4.2 Read one event from the Matched Event Record (read_msg)
The function read_msg is used by other functions in the Matching Library and by the Event
Summarizer to read one message at a time from the Matched Event Record. The file handle
DATA_FILE is used to access the Matched Event Record and it has a value which points to a
particular position in the file. The read_msg function takes no arguments and returns the next
event after the position of the file handle DATA_FILE, in a global array @message. Each line
returned by read_msg forms an element in the array @message. A message and a load
measurement as returned by the function are shown below as examples:
A message returned by read_msg:
MATCH_FLAG: 0
36524.66        10:08:44.660   NSTS2
message C(STP_A)(STP_B)(1)     STP_A   STP_B   STP_A   RSP   SSP_E4
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



A load measurement returned by read_msg:
MATCH_FLAG: 0
36522.939       10:08:42.939   NSTS2
load   D(STP_B)(STP_D)(1)      STP_B   12.81
load   D(STP_B)(STP_D)(1)      STP_D   9.67
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                                                              76


USAGE: read_msg();


6.3.4.3 Check whether the event was hidden (valid_link)
As described in section 6.3.3, the first step in matching events is to check if the link on which
the event was expected was monitored or not. The function valid_link is used to serve this
purpose. The function takes two arguments, the name of the link on which the event is
expected and the node that gives the direction of flow. The function returns a 1 or a 0
depending on whether the link was monitored in the direction given by the second argument
or not. For example if the link C(STPA)(STPB)(0) was monitored towards STPA and not
towards STPB, then
valid_link(‘C(STPA)(STPB)(0)’,’STPA’) will return 1, whereas
valid_link(‘C(STPA)(STPB)(0)’,’STPB’) will return 0.


6.3.4.4 Obtain the time stamp of an event (msg_time)
The times at which the events occurred are used by the matching functions to find out if they
are in the time period of interest. These times are also used by the write_timer function to
calculate the observed values of timers. The function msg_time takes the line in the event
containing the time stamp as its argument and returns a scalar, which is the time in seconds
and milliseconds. For example if @message contains the following:
MATCH_FLAG: 0
36524.66        10:08:44.660    NSTS2
message C(STP_A)(STP_B)(1)     STP_A    STP_B   STP_A   RSP   SSP_E4
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

and if the function msg_time is used as below to obtain the time stamp in the scalar variable
$time,
$time=msg_time($message[1]);
The variable $time will now contain „36524.66‟.


6.3.4.5 Obtain the parameters of an event (get_params)
After reading an event, its parameters must be matched against the expected event. The
function get_params takes two arguments, the line in the event returned by the read_msg
function that contains the parameters and one of the two words „message’ or ‘load’ to specify
                                                                                               77


if the event is a message or a load measurement. The function returns the parameters in the
event as individual elements of an array. For example if @message is as shown in the
previous section, the parameters of the event can be obtained using the function as:
@message_params=@{&get_params($message[2],'message')
The array @message_params will now contain „C(STP_A)(STP_B)(1)‟, „STP_A‟, „STP_B‟,
„STP_A‟, „RSP‟, „SSP_E4‟ as its six elements. Note that the number of elements of an array
in Perl need not be fixed.


6.3.4.6 Deal with test actions (test_action)
This function is introduced in the Section 6.1.2.3.3 and is used to write the test action into the
output files produced by the Specific Analyzer. The test_action function takes two
arguments, the line number of the test action in the Expected Behavior and the rest of the
line. An example is shown below:
test_action(51,"fail_link(D(STP_B)(STP_D)(0))")
The function writes the two arguments in to the missing and Hidden Event Lists, the
parameter observation list and the Expanded Expected Behavior. The function always returns
a 1.


6.3.4.7 Match an expected message (find_msg)
The findmsg function is used to match an expected message in the Actual Event Record. The
Translator converts the SEBEL findmsg function in the Expected Behavior to the findmsg
function in the Matching Library. The SEBEL findmsg function is described in the Section
4.1.5.1. The function in the Matching Library takes as arguments the line number of the
findmsg function in the Expected Behavior and the arguments of the SEBEL findmsg
function. An example is shown below:
findmsg(52,"D(STP_B)(STP_D)(1)","STP_D","STP_B","STP_D","COO","D(STP_B)(STP_D)(0)")



The function returns 1, 2 or 3 depending on whether the result of the matching process was a
success, a failure or inconclusive. The algorithm used by the function is described below:
       1. Save the time in the variable $start_time and the position of the file handle
          DATA_FILE in the variable $start_fp at the beginning of the matching process.
                                                                                             78


   2. Print the event in the Expanded Expected Behavior file.
   3. Unless the link is a wildcard, check if the link was monitored. If the link was not
       monitored, print it to the Hidden Event List, print the word „HIDDEN‟ in the
       Expanded Expected Behavior next to the event and return 2 (inconclusive). If the link
       was monitored, proceed to step 4.
   4. If the end of the Matched Event Record is reached or $time is greater than the time of
       the next test action $next_action_time, go to step 8. Otherwise, proceed to step 5.
   5. Read the next event in the Matched Event Record using the read_msg function. If the
       event is a message and its match flag is 0, go to step 6. If not, go back to 4.
   6. Obtain the time stamp of the message using the msg_time function. If the time is less
       than $next_action_time and all the non-wildcard parameters of the expected message
       match those in the read message, proceed to the next step. If not go back to 4.
   7. If there were any wildcards among the arguments to the function, set the match flag
       of the message in the Matched Event Record to „*‟. If there were no wildcards, set the
       math flag to 1. Print the word „FOUND‟ in the Expanded Expected Behavior next to
       the event and return 1.
   8. If this step is reached, the message has not been matched. Print the event in the
       Missing Event List and print the word „NOT FOUND‟ in the Expanded Expected
       Behavior next to the event. Set the value of $time to $start_time and the file handle to
       $start_fp (refer to step1) and return 3.


6.3.4.8 Match an expected load measurement (assert_load)
The assert_load function is used to match an expected load measurement in the Actual Event
Record. The Translator converts the SEBEL assert_load function in the Expected Behavior
to the assert_load function in the Matching Library. The SEBEL assert_load function is
described in section 4.1.5.2. The function in the Matching Library takes as arguments the line
number of the assert_load function in the Expected Behavior and the arguments of the
SEBEL assert_load function with quotes around them. An example is shown below:
assert_load(116,"D(STP_B)(STP_C)(0)","STP_C",20);
                                                                                             79


The function returns 1, 2 or 3 depending on whether the result of the matching process was a
success, a failure or inconclusive.
The Matching Library function assert_load finds all the load measurements in the time
interval as specified in the implementation overview of the Translator section 6.1.2.5.1.3 on
the given link.
If exp_load is the expected load and data_load is the load value found in the actual data, the
actual load value is said to match the expected load value if:
          |exp_load – data_load|  0.2*exp_load        OR
          |exp_load – data_load|  5
where exp_load and data_load are given as the percentage of the maximum load on the link.
In the Expected Behavior, sometimes the link on which the load is to be measured is given as
a link-set i.e., two links. For example:
5. assert_load(D(STP_A)(STP_C), STP_C, 10)



But there are two links in the link-set – D(STP_A)(STP_C)(0) and D(STP_A)(STP_C)(1).
The assert_load function calls itself twice – once for each load. This is equivalent to:
assert_load(D(STP_A)(STP_C)(0), STP_C, 10)
assert_load(D(STP_A)(STP_C)(1), STP_C, 10)



The load on the link-set is said to match the actual load only if the loads on each of the two
links match the actual loads.
The algorithm used by the function is described below:
   1. Save the time in the variable $start_time and the position of the file handle
       DATA_FILE in the variable $start_fp at the beginning of the matching process.
   2. Check if the link or link-set was monitored. If not monitored, print the event to the
       Hidden Event List, print the word „HIDDEN‟ in the Expanded Expected Behavior
       next to the event and return 2 (inconclusive). If monitored, proceed to step 3.
   3. If the link on which the load match is to be made is a link-set consisting of two links,
       call assert_load for each of these links. Return 1 only if both the function calls return
       1. Return 3 otherwise. If it is a single link, proceed to 4.
   4. Print the event in the Expanded Expected Behavior file.
                                                                                              80


   5. If the end of the Matched Event Record is reached or $time is greater than the time of
       the next test action $next_action_time, go to step 9. Otherwise, proceed to step 6.
   6. Read the next event in the Matched Event Record using the read_msg function. If the
       event is a load measurement, go to step 7. If not, go back to 5.
   7. Obtain the time stamp of the message using the msg_time function. If the time is less
       than $next_action_time and the link in the read load measurement is the right one,
       proceed to the next step. If not go back to 5.
   8. Perform a match of the load measurement against the expected value as described in
       the beginning of the section and print the result of the match to the Parameter
       Observation List as described in section 6.2.4.5. Go back to 5.
   9. Set the value of $time to $start_time and the file handle to $start_fp (refer to step1). If
       there were load measurements for the required link in the specified time period, go to
       step 10. If there were no load measurements, go to step 11.
   10. If there was at least one load measurement that matched the expected value, return 1.
       If there was no load measurement that matched the expected value, return 3.
   11. Print the event to the Parameter Observation List with the phrase “LOAD
       MEASUREMENT NOT FOUND” and Return 2.


6.3.4.9 Obtain the value of a timer observation (write_timer)
The write_timer function is used to calculate the observed timer values in the actual data. The
Translator converts the SEBEL waitfor function along with a findmsg function in the
Expected Behavior to the write_timer function in the Matching Library. The SEBEL
functions are described in sections 4.1.2.1 and 4.1.5.1. The write_timer function takes as
arguments the line number of the waitfor, the time when the timer is started, the arguments of
the waitfor (the name of the timer and the name of the particular STP), the name of the
function (findmsg) that the waitfor causes and all the arguments of that function. An example
is shown below:
write_timer(143,$waitfor_time[0],"T10","STP_A","findmsg",144,"C(STP_A)(
                              STP_B)","STP_B","STP_A","STP_B","RSP","STP_C");
                                                                                             81


The function returns 1, 2 or 3 depending on whether the result of the matching process of the
function in the write_timer (findmsg) was a success, a failure or inconclusive. The algorithm
used by the write_timer function is described below:
    1. Save the time in the variable $pre_wait_time and the position of the file handle
        DATA_FILE in the variable $pre_wait_fp at the beginning of the matching process
        and save the time of starting the timer in the variable $start_time.
    2. Call the function (findmsg) in the write_timer function with its parameters and save
        the value of $time when the function returns.
    3. If the function returns 1, the value of the timer is $time - $start_time. Write the timer
        observation to the Parameter Observation List based on the value returned by the
        function.
    4. Unless the waitfor function is inside a while loop, set the value of $time to
        $pre_wait_time and the file handle to $pre_wait_fp (refer to step1). If the waitfor is
        outside a while loop, it could cause multiple events, each of which must be searched
        for starting from the same time. This should not be done if the waitfor is inside a
        while loop because the messages happen one after the other.
    5. Return the value returned by the function in the write_timer (1, 2 or 3).
                                                                                             82


7 Event Summarizer
The Event Summarizer is the program that processes the Matched Event Record, Expanded
Expected Behavior, Missing and Hidden Event Lists. It produces the Unexpected Event List
for the test run and also calculates high-level statistics about the numbers of events based on
the outcomes of the matching process. The internal operation details are given in section 7.1
and the external interfaces to the Event Summarizer are described in sections 7.2 and 7.4.
7.1 Operation
The Event Summarizer performs the following functions:
   Produce the Unexpected Event List from the Matched Event Record
   Calculate the numbers of expected, missing, hidden and unexpected events
These functions are described in the following sections.


7.1.1 Produce the Unexpected Event List
The messages in the Matched Event Record have their match flags set to 0 or * or 1 based on
whether they were matched to expected messages or not. All messages with their match flags
set to 0 are unexpected messages. As explained in the section about the Matching Library
6.3.3, the Event Summarizer writes all the unexpected messages from the Matched Event
Record into the Unexpected Event List (UEL) in the order in which they appear in the
Matched Event Record. The function read_msg from the Matching Library is used to
produce the UEL. The procedure is shown in Figure 7.1.

           Matched              Find all messages with                Unexpected
            Event                  Match Flag = 0                       Event
           Record                                                        List

              Figure 7.1 Procedure of producing the Unexpected Event List

7.1.2 Calculate event statistics
The Event Summarizer produces the Event Number File, which contains the numbers of
expected, missing, hidden and unexpected events. The Event Number File also contains the
numbers of such messages based on the SS7 message type. These are discussed in the
                                                                                           83


following sections. The numbers of such messages based on the SS7 type are saved in hash
tables indexed by the SS7 types in each of these cases.
7.1.2.1 Expected Events
The numbers of Expected messages and load measurements are calculated from the
Expanded Expected Behavior.
7.1.2.2 Missing Events
The numbers of missing messages and mismatched load measurements are calculated from
the Missing Event List.
7.1.2.3 Hidden Events
The numbers of hidden messages and load measurements are calculated from the Hidden
Event List.
7.1.2.4 Unexpected Messages
The numbers of unexpected messages are calculated while the Unexpected Event List is
being generated from the Matched Event Record.


7.2 Command Usage
perl event_summarizer testxx date
Refer to Section 5.3.2 for more details.


7.3 Inputs
The Event Summarizer takes as inputs the Matched Event Record, the Expanded Expected
Behavior, the Missing Event List and the Hidden Event List for the particular run of the test.
These files are described in the section describing the outputs produced by the Specific
Analyzer 6.2.4.
The Event Summarizer produces two outputs, the Unexpected Event List and the Event
Numbers File as shown below:
                                                                                                   84



                             Expanded Expected            Missing Event List
                                 Behavior


         Matched Event Record                                                  Hidden Event List




                                             Event
                                           Summarizer




                       Unexpected Event List         Event Numbers File


                  Figure 7.2 Inputs and outputs to the Event Summarizer



7.4 Outputs produced
The Event Summarizer produces two output files, which are described below:


7.4.1 Unexpected Event List:
The Unexpected Event List is the list of all messages in the Matched Event Record, whose
„MATCH FLAG‟ is 0.
An example UEL is shown below:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MATCH_FLAG: 0
52293.776       14:31:33.776      NSTS2
message D(STP_B)(STP_D)(1)       STP_D    STP_B   STP_D     TFP     STP_C
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MATCH_FLAG: 0
52311.064       14:31:51.064      NSTS2
message C(STP_A)(STP_B)(1)       STP_A    STP_B   STP_A     TFP     STP_C
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                                                           85


7.4.2 Event Numbers File
This file contains the numbers of expected messages and loads based on the outcome of their
matching with the actual data (found, not found, hidden or load measurement not available)
and the number of unexpected messages. The numbers for messages are given in two levels
of detail. The first is for all messages and the second is based on individual SS7 message
types.
7.4.2.1 All events
There are twelve lines in the ENF, and each gives the total number events in the test of the
following types:
   1. Events (messages and load measurements) in the Actual Event Record.
   2. Messages in the Actual Event Record.
   3. Unexpected messages in the Actual Event Record.
   4. Messages in the Actual Event Record as for line 2, but only those that matched an
         expected message with a wildcard for one or more parameters.
   5. Messages in the Actual Event Record as for line 2, but only those that matched an
         expected message without any wildcard parameter.
   6. Messages in the Expanded Expected Behavior that were not matched in the actual
         data.
   7. Messages in the Expanded Expected Behavior.
   8. Load measurements in the Expanded Expected Behavior that were mismatched in the
         actual data.
   9. Expected load measurements in the Expanded Expected Behavior.
   10. Messages in the Expanded Expected Behavior that were hidden.
   11. Load measurements in the Expanded Expected Behavior that were hidden.
   12. Load measurements in the Expanded Expected Behavior for which there was no load
         measurement available in the Actual Event Record in the required time period in spite
         of the link being monitored.
The relevant lines from an ENF are shown here:
total events:746
total messages:            346
messages unexpected: 52
messages wildcard matched: 214
                                                                                      86

messages matched without wildcard: 80
messages missing: 41
messages expected: 239
loads missing: 0
loads expected: 150
messages hidden: 145
loads hidden: 14
no measurement: 60


7.4.2.2 Messages based on type
There are two types of outcomes listed from the thirteenth line onwards, one is for the
expected messages and the other is for messages in the Actual Event Record.

7.4.2.2.1 Expected messages:
For each expected message type in the Expected Behavior, along with the SS7 message type,
the numbers of the following are given in the ENF:
   1. Messages of this type in the Expanded Expected Behavior
   2. Messages of this type in the Expanded Expected Behavior that were not found in the
       Actual Event Record and
   3. Messages of this type in the Expanded Expected Behavior that were hidden


The relevant lines from an ENF are shown here:
exp_msg_type:COA     expected:15 missing:0           hidden:2
exp_msg_type:COO     expected:15 missing:1           hidden:2
exp_msg_type:RCP     expected:6     missing:2        hidden:2
exp_msg_type:RCR     expected:6     missing:6        hidden:0
exp_msg_type:RSP     expected:12 missing:6           hidden:3
exp_msg_type:RSR     expected:3     missing:2        hidden:1
exp_msg_type:SLTM expected:23 missing:19             hidden:4
exp_msg_type:TCA     expected:32 missing:2           hidden:30
exp_msg_type:TCP     expected:20 missing:1           hidden:16
exp_msg_type:TCR     expected:33 missing:0           hidden:25
exp_msg_type:TFA     expected:1     missing:0        hidden:0
exp_msg_type:TFP     expected:28 missing:0           hidden:17
exp_msg_type:TFR     expected:45 missing:2           hidden:43
                                                                                      87


7.4.2.2.2 Messages in the Actual Event Record:
For each message type seen in the Actual Event Record, the following numbers are given in
the ENF along with the SS7 message type:
   1. Unexpected messages of this type in the Actual Event Record
   2. Messages of this type in the Actual Event Record that were matched to an expected
       message without any wildcard parameter.
   3. Messages of this type in the Actual Event Record that were matched to an expected
       message with one or more wildcard parameters.


The relevant lines from an ENF are shown here:
actual_msg_type:COA         unexpected:0         not_wildcard:13       wildcard:0
actual_msg_type:COO         unexpected:0         not_wildcard:13       wildcard:0
actual_msg_type:RCP         unexpected:0         not_wildcard:10       wildcard:0
actual_msg_type:RSP         unexpected:42        not_wildcard:11      wildcard:166
actual_msg_type:TCA         unexpected:4         not_wildcard:0        wildcard:0
actual_msg_type:TCP         unexpected:1         not_wildcard:14       wildcard:0
actual_msg_type:TCR         unexpected:2         not_wildcard:8        wildcard:0
actual_msg_type:TFA         unexpected:0         not_wildcard:0        wildcard:32
actual_msg_type:TFP         unexpected:3         not_wildcard:11       wildcard:16
                                                                                              88


8 Report Generator
The Report Generator performs statistical analysis of the timer observations and load
measurements in the test results and also generates a final report of the analysis of the results
of a particular test run in HTML format. HTML was chosen because the reports are best
displayed as tables using different colors and HTML code for such a display is easy to be
produced automatically and is highly portable. The internal operation of the Report
Generator is explained in section 8.1, the external interfaces to the Report Generator are
described in section 8.2 and the output generated is described in section 8.3.
8.1 Implementation
The Report Generator performs the following functions:
   Obtain and write out statistics about expected, missing, hidden and unexpected events
   Obtain and organize timer observations and load measurements from the Parameter
    Observation List
   Write out the above information in the form of tables


These are described in the following sections.
8.1.1 Report event statistics
The report generator produces HTML tables about expected, missing, hidden and unexpected
events as explained in section 8.3. These tables are obtained from the Event Number File.
This is accomplished using the function get_and_write_event_stats, which uses template
functions to write HTML table headers and table rows.


8.1.2 Obtain and organize parameter observations
The Parameter Observation List contains all the observed timer values and the observed load
measurements. The function get_parameter_observations is used to read these observations
and produce two data structures – one for timer observations and the other for load
measurements, that can be used to easily generate the required statistics.
8.1.2.1 Timer observations
The function produces a data structure called timer_list, which is a four dimensional table
containing the list of observations for each timer of each STP for every activation of the
timer. The data structure has three indices. The first index is the name of the STP and the
                                                                                             89


second is the name of the timer. The third index will be discussed in sections 8.1.2.1.1 and
8.1.2.1.2. As will be discussed in Section 8.3, there are two types of timer observations-
inside a while loop and not inside a while loop. These two cases are discussed below:

8.1.2.1.1 Not inside a while loop
If a timer is not inside a while loop the activation of the timer can cause multiple events. As
explained in section 8.3, the observed timer value for the first of these multiple events is
important. Hence, the observations for different timer activations should be differentiable.
The function uses the time when the timer was activated as the third index. So, the entry of
this table will be the list of all observations made for a timer (second index) of an STP (first
index) for a particular activation (third index).

8.1.2.1.2 Inside a while loop
If a timer is used inside a while loop, it is always used inside a while loop and all
observations are equally important. Hence, the third index is set to the word „while‟. The
entry of this table will be the list of all observations made for a timer of an STP.


8.1.2.2 Load measurements
The function produces a data structure called load_obs, which is a four dimensional table
containing the list of load measurements obtained from the Actual Event Record after a
particular test action, for a particular link and a particular line number in the Expected
Behavior. The data structure has three indices. The first index is the number of the test action
after which the load was measured. The second index is the line number of the event in the
Expected Behavior and the third index is the link name along with the node specifying the
direction.


8.1.3 Write timer observations
The function write_timer_stats is used to produce the tables for the timers as will be
described in section 8.3. The data structure timer_list as explained in section 8.1.2.1 is used
to obtain statistics like the minimum, maximum and the average values of the timers. These
                                                                                             90


statistics are written into the final report using template functions to produce code for HTML
tables.


8.1.4 Produce the detailed analysis table
The report generator uses the Expanded Expected Behavior to produce the detailed analysis
table (Section 8.3). The statistics regarding the load measurement matching results are
obtained from the data structure load_obs described in section 8.1.2.2. The Matching Library
function read_msg is used to get the messages from the Unexpected Event List.


8.2 Usage and Inputs
perl statalyzer testxx date
Refer to Section 5.3.2 for more details.
The report generator takes the parameter observation list, Expanded Expected Behavior,
Unexpected Event List and the event number file as inputs. The report generator processes
these files and produces one output file, in HTML format as shown in Figure 8.1.



                                                         Expanded Expected
                       Event Number File                     Behavior



           Parameter Observation                                     Unexpected Event List
                   List




                                            Report
                                           Generator




                                           Test Report


                   Figure 8.1 Inputs and output of the Report Generator
                                                                                             91


8.3 Output Produced
The report contains the results of the test analysis in HTML format, and these include two
levels of detail:
   The Overview level provides a broad overview of whether the System Under Test (STP)
    passed or failed the test.
   The Detailed level describes whether the STP passed or failed each line of the Expected
    Behavior, when unexpected events occurred, and provides links to intermediate results
    that are produced during the analysis.
Sections 8.3.1 and 8.3.2 describe concepts that apply to both levels, while Section 8.3.3
describes the overview level of reports, and Section 8.3.4 describes the detailed level of
reports.
8.3.1 Classification of test results
A test of the STP may result in a pass, fail, or inconclusive result. The STP passes the test
when there are no missing, unexpected, or hidden events. The STP fails the test when there
are missing or unexpected events, although the severity of this failure requires human
interpretation of the test results. A test is inconclusive if there are no missing or unexpected
events, but there were hidden events.
        The pass/fail status reflects whether the observed data matched what was expected. A
mismatch may be due to either the STP failing, the monitoring equipment failing, the test not
being performed properly, or the Expected Behavior being incorrect. Attributing the cause of
failure to any of these sources requires human interpretation, and is beyond the capabilities of
ASTRA. Confidence in the Expected Behavior can be improved by analyzing the results of
multiple test runs for STPs that behave properly, and observing no missing or unexpected
events for these test runs.


8.3.2 Color coding of test results
Individual items in the report are color coded to reflect how they contributed to the overall
test result. The color codes used and their meaning is explained in the table below:
                                                                                            92


                              Table 3: Description of colour codes

COLOR        DESCRIPTION
Green        Item was expected and was found in the actual data and contributed to a test
             pass
Red          Item was unexpected or was missing and contributed to a test failure
Gray         Item was hidden (link was not monitored) and contributed to the test being
             inconclusive
Dark
             Load measurement was not found in the actual data
Gray


If a load measurement was not found, it is often because the monitors stopped collecting data
before the end of the test.


8.3.3 Overview level of reports
The overview level starts with the overall test result (pass/fail/inconclusive). If the overall
result is a failure, then the report includes a numerical measure of the “severity” of the
failure. The severity measures the ratio of unexpected or missing events to matched events,
so STPs that almost behaved as expected will fail with low “severity”. Note that this measure
of severity does not necessarily indicate the impact that the failure would have in an
operational network. The exact formula used for calculating the severity is as follows:
        num  2n
S           me
       3nmnw 3nmxb


Where S is the measure of severity, num is the number of unexpected messages, nmnw is the
number of messages in the Actual Event Record matched with no wildcards, nme is the
number of missing events (messages and load measurements) in the Expanded Expected
Behavior and nmxb is the number of matched events in the Expanded Expected Behavior. The
2:1 weighting of missing events to unexpected events is fairly arbitrary, but reflects the
presumed precedence of missing events: a STP should still be useful if it does everything it is
                                                                                             93


supposed to (no missing events), even if it does some additional things (some unexpected
events).
       The overview level then summarizes the classification of events that were expected or
observed during the test.     The following sections describe the remaining parts of the
overview level, in the order in which they appear in the overview.
8.3.3.1 Message overview
The messages part of the overview has four tables that summarize all messages involved in
the test. The first two tables classify those messages according to whether they were missing,
unexpected or matched. The next two tables classify those messages according to their SS7
type (e.g. TFR or COO). All tables also give the numbers of events as a percentage.
Table 1: Expected Messages:
The first table describes messages that were expected in the Expected Behavior. It shows
whether those messages were missing, hidden, or matched in the actual data. The numbers in
this table refer to the number of lines of the Expanded Expected Behavior that fell into those
three categories. Ideally, there should be no missing events, and the ratio of number of
missing events to the number of matched events indicates the degree of failure of a test. An
example of such a table is shown below:



                                        Missing Hidden Matched

                            Number      199      464      345
                            Percentage 19.74     46.03    34.23


Note that if an event was missing, then ASTRA still attempts to match the events that the
missing event causes. This is useful because there could be instances when an event is
missing from the actual data, but events that it caused are observed in the actual data. This is
due to the monitor not properly recording events, rather than the STP itself malfunctioning.
This is also highlighted in the table that summarizes the expected messages: If an event is
missing and the events that it causes are also missing, then the number of events in the
missing column will be larger (and hence more serious) than if only the parent event were
missing.
                                                                                             94



Table 2: Messages in the actual data:
The second table describes the messages in the actual data. In contrast to the previous table
that related to the Expected Behavior, this table also includes messages that were unexpected.
This table classifies actual messages as being either unexpected or matched with, or without,
wildcards. Ideally there should be no unexpected events. Matching with wildcards is done in
describing the Expected Behavior of some tests because those messages are not relevant to
the test. The ratio of the number of unexpected messages to the number of messages that
were matched without wildcards indicates the degree of failure of a test. An example of such
a table is shown below:


                                         Matched               Matched
                           Unexpected
                                         Without Wildcards With Wildcards
               Number      25            1581                  23
               Percentage 1.53           97.05                 1.41




Tables 3 and 4: Based on message type:
Tables 3 and 4 are similar to tables 1 and 2, in that the first table summarizes messages in the
Expected Behavior, and the second table summarizes messages in the actual data. Both of
these tables classify the messages by their SS7 type (e.g. TFR or COO). These tables are
provided to help an analyst determine what types of messages were unexpected or missing.
Examples of these tables are shown below:



                                 Message Type Missing Hidden Matched

                   Number                        22      0          0
                                 CBD
                   Percentage                    100     0          0
                   Number                        1       0          13
                                 COA
                   Percentage                    7.14    0          92.86
                   Number        COO             9       8          13
                                                                                      95


                   Percentage                30      26.67   43.33
                   Number                    4       0       1
                                RCP
                   Percentage                80      0       20
                   Number                    109     0       47
                                RSP
                   Percentage                69.87   0       30.13


                                             Matched              Matched
                   Message Type Unexpected
                                             Without Wildcards With Wildcards
      Number                      2          0                    0
                   CBA
      Percentage                  100        0                    0
      Number                      6          0                    0
                   CBD
      Percentage                  100        0                    0
      Number                      0          13                   0
                   COA
      Percentage                  0          100                  0
      Number                      0          13                   0
                   COO
      Percentage                  0          100                  0
      Number                      0          6                    0
                   RCP
      Percentage                  0          100                  0
      Number                      9          884                  0
                   RSP
      Percentage                  1.01       98.99                0


8.3.3.2 Load overview
The load overview shows how many load measurements in the Expanded Expected Behavior
were matched in the actual data. Both the numbers and percentages of the loads that were
matched, mismatched or hidden are provided in the table. An example is shown below:



                            Mismatched Hidden Matched No Measurement
                                                                                             96


            NUMBER             5             0        115       20
            PERCENTAGE 4.17                  0        79.17     16.67
8.3.3.3 Timer overview
A common element of protocol behavior is that a certain time after one event occurs, the STP
should respond with another event. For example, periodically sending a message, or timing
out when waiting for a message. The interval that the STP is expected to wait for is a timer
parameter. Part of the analysis is to infer the STP‟s timer values by observing its behavior. If
any timers appeared in the Expected Behavior for the test, then the Timer Overview reports
any observed values of those timers. The timer overview has separate tables for the observed
values of timers from each STP involved in the test. These tables report the range, average,
and number of samples of each timer.
       For each STP, there may be two tables. To understand the difference between these
tables, it is necessary to review how timers may be used in the Expected Behavior: One
application of timers is where a STP periodically sends a message. Such timers appear in
while loops, and observations of their value will only appear in the “All events” table.
Another application of timers is where they do not cause messages to be sent periodically,
but result in one or more messages being sent. For example, after a timer expires, a STP may
be required to send messages to multiple neighboring STPs. The first message that the STP
sends indicates that its internal timer has expired, although the times when the STP sends
messages to the other neighboring STPs may also be important if the STP is required to send
the messages within a certain time. Consequently, there are two sets of measurements for this
second application of timers: Measurements relating to the first event observed, and
measurements relating to all events observed (including the first event). Example of both
tables for an STP are shown below:


                         All Events
                         TIMER AVG MIN MAX SAMPLES
                         T10       29.769 26.754 30.035 18
                         T11       16.330 7.490 77.482 44
                                                                                            97


                          First Event
                          TIMER AVG MIN MAX SAMPLES
                          T11       25.365 7.490 77.480 8


For more information about the distribution of the observed timer values, the analyst can
consult the “Parameter Observation List”, which can be accessed through a link at the end of
the report.


8.3.4 Detailed analysis
The detailed analysis section of the report shows each expected and unexpected event for the
test. Each event is listed on a separate row, and the background is color coded as described in
Section 8.3.2. The analyst can scan the table to spot red items and then pay attention to those
items to determine why the test failed.
        Expected events are listed in the first column of the table, unexpected events in the
second column, and any observations relating to expected events in the third column. The
test actions are also listed on separate rows with a blue background. For load measurements,
the observations column has the form:
E=25; A=24.95; M=100% RANGE=[22.31,26.33]; S=6

Where E refers to the expected load (as a percentage), A refers to the average actual load, M
indicates the percentage of the actual load observations that matched what was expected.
This is followed by the range of the actual load observations, and the number of samples S of
the actual load observations. Sections 8.3.4.1 to 8.3.4.4 describe the format of the events in
the table based on the result of their matching with the actual data.


8.3.4.1 Missing events
Missing events are shown in the “expected event” column (first column) and are shown with
a red background. A missing event may be noted as having occurred “0 times” in the
“observations” if the event was in a while loop in the Expected Behavior.
Ex:
                                                                                               98


                                                                                     0
      157. findmsg(D(STP_A)(STP_D),STP_A,STP_D,STP_B,RSP,STP_C)
                                                                                     TIMES



8.3.4.2 Hidden events
Hidden events are shown with the corresponding line from the Expected Behavior
highlighted in gray.

  141. findmsg(A(STP_B)(SCP_E2),SCP_E2,STP_B,SCP_E2,TFR,STP_C)



8.3.4.3 Matched events
An EB line that refers to a message that was matched in the actual data is listed in green, and
may include in the “observations” column the number of times that the message was matched
(if the line occurred in a while loop). If the event is a load measurement, the statistics about
the observations is provided in the third column. As discussed in Section 6.3.4.8, an expected
load measurement is considered to match the data if it matches at least one measurement in
the actual data.
Ex:

  146. findmsg(C(STP_A)(STP_B),STP_B,STP_A,STP_B,RSP,STP_C)                          6 TIMES



                                                               E=20;     A=24.96;     M=50%
   226. assert_load(C(STP_A)(STP_B)(1),STP_A,20)
                                                               RANGE=[24.24,25.38]; S=4



8.3.4.4 Unexpected messages
When unexpected messages occur, they are listed immediately after the last test action that
preceded them, and may have caused them. Unexpected messages are listed with the time
when they occurred so that the analyst can consult the Actual Event Record and other
monitor data to find more information about these messages.
Ex:
          TEST ACTION - 122 fail_link(D(STP_B)(STP_C)(0)) TIME: 37702
                                                                                             99


          37707.824                     10:28:27.824                    NSTS2
          message       link=[C(STP_A)(STP_B)(0)=>STP_B]         [OPC=STP_A]
          [DPC=STP_B] RSP STP_D

          37737.827                     10:28:57.827                    NSTS2
          message       link=[C(STP_A)(STP_B)(0)=>STP_B]         [OPC=STP_A]
          [DPC=STP_B] RSP STP_D



The detailed analysis section of the report ends with links to files that are used internally by
ASTRA for the analysis. These include the Missing, Unexpected, and Hidden Event Lists,
the Parameter Observation List, and the Matched Event Record. The analyst may wish to
consult these for further information about the test.
                                                                                             100


9 Conclusion and future work
    A methodology to automate SS7 STP interoperability test result analysis was developed
and implemented in software. The software, called ASTRA (Automated SS7 Test Results
Analyzer), is capable of reducing the time required to analyze test results by multiple orders
of magnitude while eliminating human errors and labor.
    A new language called SEBEL (SS7 Expected Behavior Expression Language) was
developed to formally describe the expected behavior of the STPs in response to the tests.
    ASTRA will need to be updated to incorporate any new tests and enhancements to
SEBEL. ASTRA will also need to be updated to accommodate any new monitoring
equipment because the formats used to save test data varies from monitor to monitor.
    Though the analysis methodology was developed for STP interoperability testing, it can
also be used for SS7 protocol conformance testing. Hence, ASTRA can be extended to
include conformance tests without any major changes.
                                                           101



                          Appendix A: File naming scheme

Recorded Times of Test Actions          testxx.rta
Clock Differences File                  testxx.cdf
Test Network Configuration              testxx.tnc
Pointcode Assignment File               testxx.paf
Link Mapping File                       testxx.lmf
Expected Behavior                       testxx.exb
Formatter                               format
Symbol Replacing Library                replace_lib.pm
Translator                              Translator
Actual Event Record                     testxx.aer
Specific Analyzer                       testxx.anz
Matching Library                        matching_lib.pm
Matched Event Record                    testxx.mer
Missing Event List                      testxx.mel
Hidden Event List                       testxx.hel
Parameter Observation List              testxx.pol
Expanded Expected Behavior              testxx.xxb
Event Summarizer                        event_summarizer
Unexpected Event List                   testxx.uel
Event Number File                       testxx.enf
Report Generator                        report_generator
Final Report                            testxx.html
                                                                                    102



                        Appendix B: File structure format

D    /auto/BIN/analysis/                    Analysis automation software
P    /auto/BIN/analysis/format              Data Formatting
P    /auto/BIN/analysis/replacer.pm         Symbol Replacer library
P    /auto/BIN/analysis/translater          Translater
P    /auto/BIN/analysis/test##.anz          Analyzer for a test
P    /auto/BIN/analysis/stats               Statistical Analysis
P    /auto/BIN/analysis/event_summarizer    Event Summarizer
D    /auto/DATA                             Data files
D    /auto/DATA/yyyymmmdd                   Data for a test run on day dd of month
                                            mmm of year yyyy
DE   /auto/DATA/2001apr01                   Data for a test run on the 1st of April
                                            in 2001
D    /auto/DATA/yyyymmmdd/CONFIG            As for /auto/DATA/CONFIG, but for
                                            a previous testing day
D    /auto/DATA/yyyymmmdd/LOGS              As for /auto/DATA/LOGS, but for a
                                            previous testing day
D    /auto/DATA/yyyymmmdd/ANALYSIS          As for /auto/DATA/ANALYSIS, but
                                            for a previous testing day
D    /auto/DATA/yyyymmmdd/MGTS              As for /auto/DATA/MGTS, but for a
                                            previous testing day
D    /auto/DATA/yyyymmmdd/NSTS              As for /auto/DATA/NSTS, but for a
                                            previous testing day
D    /auto/DATA/yyyymmmdd/TESTCASES         As for /auto/DATA/TESTCASES, but
                                            for a previous testing day
D    /auto/DATA/ANALYSIS/                   Analysis output
F    /auto/DATA/ANALYSIS/test##.aer         Actual Event Record for test ##
                                            (produced by the Formatter)
F    /auto/DATA/ANALYSIS/test##.pol         Parameter Observation List
F    /auto/DATA/ANALYSIS/test##.mel         Missing Event List
F    /auto/DATA/ANALYSIS/test##.uel         Unexpected Event List (produced by
                                            the Unexpected Event Finder)
F    /auto/DATA/ANALYSIS/test##.obs         Observed Parameter Summary
                                            (produced by the Statistical Analysis
                                            program)
F    /auto/DATA/ANALYSIS/test##.res.html    Results of a test (produced by the
                                            Report Generator)
D    /auto/DATA/CONFIG                      Lab configuration files (files that exist
                                            before any test occurs)
F    /auto/DATA/CONFIG/stp?                 Parameter ranges for STP? (where ? =
                                            A, B, C or D)
F    /auto/DATA/CONFIG/test##.exb           Expected Behavior for a test (in text
                                            format, produced by Word)
                                                                               103


F   /auto/DATA/CONFIG/test##.exb.doc   Expected Behavior for a test in
                                       Microsoft Word format
F   /auto/DATA/CONFIG/test##.paf       SS7 Pointcode Assignments File
F   /auto/DATA/CONFIG/test##.tnc       Test Network Configuration for a test
F   /auto/DATA/CONFIG/test##.lmf       Link Mapping File for a test
D   /auto/DATA/MGTS                    Message Generator Traffic Simulator
                                       files
F   /auto/DATA/MGTS/test##_mgts?.emr   EMRs from MGTS ?
D   /auto/DATA/NSTS/                   NSTS data for current test
F   /auto/DATA/NSTS/test##_nsts#.out   Extra verbose output from NSTS #
D   /auto/DATA/TESTCASES               Test cases
F   /auto/DATA/TESTCASES/test##.tal    Test Action List
F   /auto/DATA/TESTCASES/test##.rta    Record of Test Actions
F   /auto/DATA/TESTCASES/test##.cdf    Clock Difference File
                                                                104


               Appendix C: Example Test Network Configuration

C(STP_A)(STP_B)(0)     L0
C(STP_A)(STP_B)(1)     L1
C(STP_C)(STP_D)(0)     L0
C(STP_C)(STP_D)(1)     L1
D(STP_A)(STP_C)(0)     L0
D(STP_A)(STP_C)(1)     L1
D(STP_A)(STP_D)(0)     L0
D(STP_A)(STP_D)(1)     L1
D(STP_B)(STP_C)(0)     L0
D(STP_B)(STP_C)(1)     L1
D(STP_B)(STP_D)(0)     L0
D(STP_B)(STP_D)(1)     L1
A(SSP_E1)(STP_A) L0
A(SSP_E1)(STP_B) L0
A(SSP_E2)(STP_A) L0
A(SSP_E2)(STP_B) L0
A(SSP_E3)(STP_A) L0
A(SSP_E3)(STP_B) L0
A(SSP_E4)(STP_A) L0
A(SSP_E4)(STP_B) L0
A(SSP_E5)(STP_A) L0
A(SSP_E5)(STP_B) L0
A(SSP_E6)(STP_A) L0
A(SSP_E6)(STP_B) L0
A(SCP_E1)(STP_A) L0
A(SCP_E1)(STP_B) L0
A(SCP_E2)(STP_A) L0
A(SCP_E2)(STP_B) L0
A(SSP_W31)(STP_C) L0
A(SSP_W31)(STP_D) L0
A(SSP_W32)(STP_C) L0
A(SSP_W32)(STP_D) L0
A(SSP_W33)(STP_C) L0
A(SSP_W33)(STP_D) L0
A(SSP_W34)(STP_C) L0
A(SSP_W34)(STP_D) L0
A(SSP_W35)(STP_C) L0
A(SSP_W35)(STP_D) L0
A(SSP_W36)(STP_C) L0
A(SSP_W36)(STP_D) L0
A(SCP_W31)(STP_C) L0
A(SCP_W31)(STP_D) L0
A(SCP_W32)(STP_C) L0
A(SCP_W32)(STP_D) L0
                                                                                    105


          Appendix D: Allowable message types and parameters for findmsg()

                    Message Type Parameter 1              Parameter 2
                   CBA              SLC                   -
                   CBD              SLC                   -
                   COA              SLC                   -
                   COO              SLC                   -
                   RCP              CLUSTER DEST          -
                   RCR              CLUSTER DEST          -
                   RCT              -                     -
                   RSP              DEST                  -
                   RSR              DEST                  -
                   SLTM             SLC                   -
                   SLTA             SLC                   -
                   TCA              CLUSTER DEST          -
                   TCP              CLUSTER DEST
                   TCR              CLUSTER DEST          -
                   TFA              DEST                  -
                   TFC              DEST                  Status
                   TFP              DEST                  -
                   TFR              DEST                  -
                   UDTS             CAUSE                 -


DEST is the name of a node, CLUSTER DEST is the name of a cluster (refer to section 0),
SLC is Signaling Link Code. CAUSE can at present only be the string „congestion’.
                                                                                                                                      106


                                             Appendix E: ASTRA source code
#!/usr/local/bin/perl

#USAGE: perl format prefix (ex: format test52)

#INPUT FILES: lmf, tnc, rta, pointcodes, clock_diffs, data files(NSTS verbose)
#OUTPUT FILES: actual event record (ex: test52_aer)


#Author: Ramesh Badri; email:rbadri@purros.poly.edu
#CATT, Polytechnic University
#Date: 05/31/01

use FindBin; #This and
use lib $FindBin::Bin; #this are used to tell the program that it should look for the libraries in the program's directory also

use replace_lib ();
$|=1;
$message_separator ="+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
#string signifying message beginning

%file_extension_type = (
                                   "out" => "NSTS",
                                   "log" => "STPLOG",
                                   "emr" => "EMR",
                                   );                 #map the file extensions to the corresponding data types

%msg_begin_string = (
                           "NSTSX"           => '\*\*\*\*\*\*\*\*\*\* ',
                           "STPLOG" => ' \*\*\*\*\d\d-\d\d-\d\d ',
                           "EMR" => ' \d\d\/\d\d\/\d\d',
                           );               #map the data types to the string literals at the beginning of the messages

%time_word_num = (
                         "NSTS" => 3,
                         "NSTSX" => 2,
                         "STPLOG" => 3,
                         "EMR" => 3,
                         );     #map the data type to the corresponding position of the word containing time in the
#first line of the messages

%emr_numbers=(
        "89" => "UDTS",
           ); #emr numbers that we are interested in and the message types they stand for
%unwanted_msg=(
             "RESP" => 1,
             "QRYP" => 1,
             );

($begin_time,$end_time)=&get_cutoff_times("../../DATA/$ARGV[1]/$ARGV[0]/TESTCASES/$ARGV[0].rta"); #read the starting time
and the ending time of the test from the rta file

%names_pointcodes = %{&get_symbol_hash("../../DATA/$ARGV[1]/$ARGV[0]/CONFIG/$ARGV[0].paf")}; #get the node_name - PC
table
   #keys contain the node names and the values are the pointcodes

%right_pointcodes = reverse %names_pointcodes; #has all the relevant PCs as the keys and the
#node names as values. Used for filtering.
@sorted_pointcodes=&sort_hash(\%right_pointcodes); #sort the pointcodes(needed for replacing functions)


@all_files=glob("../../DATA/$ARGV[1]/$ARGV[0]/MGTS/$ARGV[0]*.emr");
unshift @all_files,glob("../../DATA/$ARGV[1]/$ARGV[0]/NSTS/$ARGV[0]*.out");                  #get all the NSTS and MGTS EMR files with the
given prefix.

$number=1;
print "\n\nProcessing the Following Files: \n";
foreach $a_file (@all_files){                           #for each file from the above
   if($temp_type=&get_file_type($a_file)){ #if the file extension is relevant. i.e. $temp_type is not empty
                                                                                                                                            107

            print "$a_file\n";
            $handle_name="IN_FILE$number";
            $file_name{$handle_name}=$a_file;                         #open the file with file handle IN_FILE$number (ex: IN_FILE1,
IN_FILE2)
            open($handle_name,$a_file)||die "Could not open the test data file: $a_file";                           #open the input file
            $file_type{$handle_name} = $temp_type; #map file handle(key) to file type(value)
            $line{$handle_name}=<$handle_name>;                   #get the first line from each file
            $machine_name{$handle_name}=&get_machine_name($a_file); #get the machine name from th
               #e file name. test52_NSTS1.out etc - NSTS1 is the machine name
            $valid_machine_name{$machine_name{$handle_name}}=1;
            $number++;
    }
}

($valid_link_name_ref,$slc_mapping_ref)=&get_valid_links("../../DATA/$ARGV[1]/$ARGV[0]/CONFIG/$ARGV[0].tnc");
%valid_link_name=%{$valid_link_name_ref}; #get the hash of all the valid link names in the network as indices and value as 1
%slc_mapping=%{$slc_mapping_ref};#ref to hash of hash of hash $slc_mapping{node1}{node2}{L0}=link,
%link_mapping=%{&get_link_mapping("../../DATA/$ARGV[1]/$ARGV[0]/CONFIG/$ARGV[0].lmf")};

foreach $key1 (keys %link_mapping){
   foreach $value (values %{$link_mapping{$key1}}){
           unshift @monitored_links,$value; #the set of all "link\tdirection" which were monitored(we have data for these links)
   }
}
%clock_error = %{&get_symbol_hash("../../DATA/$ARGV[1]/$ARGV[0]/TESTCASES/$ARGV[0].cdf")}; #has the machine_names as
keys and
open(OUT_FILE, ">../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].aer")||die "Could not open the file $ARGV[0].aer to write
the output"; #open the output file
foreach $link_and_dir (@monitored_links){
   print OUT_FILE "link\t"."$link_and_dir\n"; #print the list of the monitored links and directions in the AER file
}


open(UNSORTED_FILE,">unsorted_output")||die "Could not open the temporary file: 'unsorted_output'";

foreach $key (keys(%file_type)){                       #for each of the input file
   until(&message_begin($file_type{$key},$line{$key})){ #until beginning of the first message
           $line{$key}=<$key>;                             #read from file
           if (not($line{$key})){delete $file_type{$key};} #remove the file if the file is empty
   }
}

%current_time=%file_type;                                #create a table with file handles as keys . This hash is used to keep track of the files
which still have data to be processed
foreach $file (keys(%current_time)){
   $current_time{$file}=&get_time($file_type{$file},$line{$file},$machine_name{$file});
}                      #store the times of the current message read from each file in the table

print "\nFormatting In Progress\n\n";
$total=0; #total number of events
$total_msg=0; #total number of messages
$filtered=0; #total number of filtered events
$filtered_msg=0; #total number of filtered messages

$filter_flag; #a global flag indicating whether the message is to be filtered out (0) or copied to the output (1)

while (@files_exist=keys(%current_time)){ #while there still are some unfinished files
  $current_file=&get_minimum(\%current_time);        #find the file wih the minimum current time
  $file_type=$file_type{$current_file};              #get its file type. %file_type and $file_type are unrelated
  $message_flag=0;                                   #message has not been read yet
  @message="";                                                    #clear the message. (MISNOMER, @event is the right name to use)
  ($msg_ref,$line{$current_file})=&read_message($current_file,$file_type,$line{$current_file});
  @message=@{$msg_ref}; #get the message from its reference. @message is global and is used in several functions

    &standardize_pointcodes($file_type, \@message); #standardize the point codes(ex:246-022-001)

    if($current_time{$current_file}){
             $total++;
             unless($total%500){print "::";}
             if(($message[3]=~/^d/)||($file_type eq 'EMR')){$total_msg++;}
                                                                                                                                     108

    } #update the numbers

    $filter_flag = &filter_message(\@message, \%right_pointcodes);                 #filter the message
    #and set the flag to true if it is a relevant message(Point Code based only)

  if ($filter_flag && $message_flag && $current_time{$current_file}){                    #if it is a relevant and complete message
             &standardize_link_names($file_type,$machine_name{$current_file},\@message); #standardize the link names and produce
2formatted lines for loads in 2 dirs (for NSTS data only). For EMR, just add the word 'message' to the 4th line
             if ($message[3]=~/^message/){      #IF it's a message then (load measurements have already been formatted)
                &format_message($file_type,$current_file,\@message,$machine_name{$current_file});}                #format the message

             if($filter_flag){      #If it is a relevant event

               if($message[3]=~/^message/){$filtered_msg++;} #update number of filtered messages
               $filtered++;     #update number of filtered events
               chomp(@message); #remove all \n
               $event_in_one_line=join 'line_glue',@message; #obtain just one line for the event. \n is substituted by 'line_glue'
               print UNSORTED_FILE "$current_time{$current_file}".'line_glue'."$event_in_one_line\n"; #print it to the temporary file
with the time in the beginning and 'line_glue' separating the time from the rest
            }
  }
  if ($file_type{$current_file} eq 'NSTS'){       #If it is NSTS
            if(eof $current_file){              #IF end of file
               delete $current_time{$current_file}; #remove the file from the records, it has been processed completely
               print "\n\nFinished Reading: ",$file_name{$current_file},"\n\n";
            }
  }

    if ($current_time{$current_file}){          #if the file has not been removed
             $current_time{$current_file}=&get_time($file_type{$current_file},$line{$current_file},$machine_name{$current_file} );
    }        #get the new current time of this file

}

close(UNSORTED_FILE);
print "\n\nSorting the Events\n";

if ($^O =~ /Win32/){ #if its a windows system
   chomp($windows_os=`ver`); #get the version of the windows OS using the DOS command "ver", into the variable $windows_os
   if($windows_os=~/Windows 2000/){ #if it's windows 200, the command is "sort unsorted_file /o sorted_file"
            system "sort","unsorted_output","/o","sorted_output";} #sort using the system command.
   elsif($windows_os=~/Windows NT/){ #if it's windows NT ver 4.0, "sort < unsorted_output > sorted_output"
            `sort < unsorted_output > sorted_output`;}
   elsif($windows_os=~/Windows 98/){ #if it's windows 98, "sort unsorted_output > sorted_output"
            `sort unsorted_output > sorted_output`;}
   elsif($windows_os=~/Windows 95/){ #if it's windows 98, "sort unsorted_output > sorted_output"
            `sort unsorted_output > sorted_output`;}
}
else { #If it's not windows, assume it is unix
   system "sort","unsorted_output","-o","sorted_output";}
unlink "unsorted_output"; #delete the 'unsorted_output' file
print "Sorting Complete\n\n";
print "Writing the Output\n\n";

open(SORTED_FILE,"sorted_output")||die "Could not open the temporary file: 'sorted_output'";
while($line=<SORTED_FILE>){ #each line has the time, and all lines of an event glued together as a single line
   @pieces=split 'line_glue',$line; #split the line around the 'line_glue'
   shift @pieces; #get rid of the time in front
   $output_line=join "\n", @pieces; #The last of @pieces has a "\n" of its own, append a "\n" to the rest of the lines
   &replace_line($output_line,\@sorted_pointcodes,\%right_pointcodes); #replace the point codes with the node names
   print OUT_FILE $output_line; #write the event to the output
}
close(SORTED_FILE);
unlink "sorted_output"; #delete the 'sorted_output' file

print "\nFormatted and filtered data written to file: '../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].aer'\n\n";
close(OUT_FILE);

print "Number of Events in the input = $total\n";
print "Number of Events in the output = $filtered\n";
                                                                                                                                           109

print "Number of Messages in the input = $total_msg\n";
print "Number of Messages in the output = $filtered_msg\n";

######################################
#USAGE: &get_cutoff_times("rta_file")
#returns the $beginning_of_test and $end_of_test from the rta file. Only events within this time range are formatted
sub get_cutoff_times{
  my ($line,$begin,$end,$two_time,$hours_time);
  open(RTA_FILE,$_[0])||die "Could not open the test action record file $_[0]";
  while($line=<RTA_FILE>){ #while there are lines to read from the rta file
           if($line=~/\$beginning_of_test/){ #if the beginning_of_test label is found
              $line=~/[\d\:\.]+/;   #match the time (consisting of digits, ':' and '.')
              $hours_time=$&;          #time in hrs is the matched part
              $two_time=$hours_time; #$two_time is modified in &get_time
              $begin=&get_time(1,$two_time); #get the time in both formats
              $begin=~s/\s*\Q$hours_time//; #get the time in sec.msec format
              last;               #get out of the loop
           }
  }
  unless($begin){die "The beginning of the test was not found in the rta file: $_[0]\nThe expression in the rta file must be- hr:min:sec
$beginning_of_test test_begin()";} #if beginning is found, error message

   while($line=<RTA_FILE>){
            if($line=~/\$end_of_test/){ #do the same as above for hte end_of_test
               $line=~/[\d\:\.]+/;
               $hours_time=$&;
               $two_time=$hours_time;
               $end=&get_time(1,$two_time);
               $end=~s/\s*\Q$hours_time//;
               last;
            }
   }
   unless($end){die "The end of the test was not found in the rta file: $_[0]\nThe expression in the rta file must be- hr:min:sec $end_of_test
test_end()";}

    return ($begin,$end); #return the beginning time and ending time of the test
}

######################################
#USAGE: ($valid_links_ref,$slc_mapping_ref)=&get_valid_links("tnc_file_name")
#returns the reference to the hash of names of all the links in the network as indices, values =1
#returns the hash of hashes of hashes with node1 as index1, node2 as index2, SLC of a link as index3 and the link as the value. ex:
$slc_mapping{'STPA'}{'SSP1'}{'L0'}='A(STPA)(SSP1)'

sub get_valid_links{
  my (@all_lines,@pieces,$line,%func_valid_links,%func_slc_map);
  open(LINK_FILE,$_[0])||die "Could not open the test network config. file $_[0]"; #open the TNC file
  @all_lines=<LINK_FILE>; #read the TNC file into an array
  close(LINK_FILE);
  foreach $line (@all_lines){ #for each line in the TNC file
           unless($line=~/^\s*\Z/){
              chomp($line); #remove the \n
              @parts=split(/\s+/,$line); #split the line around white space
              unless(@parts==2){ #there must be 2 parts (link L[01])
                       print "The line: $line in the TNC $_[0] is not in the right format\n";}
              $func_valid_links{$parts[0]}=1; #the value of the hash with the index as the link name
              @pieces=split(/\(/,$parts[0]); #split the link name around (, we get C, STPA), STPB), 0) from C(STPA)(STPB)(0)
              shift @pieces; #get rid of the link type. we now have STPA), STPB), and 0)
              $pieces[0]=~s/\)//; $pieces[1]=~s/\)//; #remove the ) from the node names. we have STPA, STPB and 0)
              unless(($names_pointcodes{$pieces[0]})&&($names_pointcodes{$pieces[1]})){ #the node names must be present in the
pointcodes file
                       print "The nodes given in the line $line\n in TNC file $_[0] cannot be found in the pointcodes file\n";}
              unless($parts[1]=~/L[01][012345]*/){ #The SLC value ranges between L0-L15
                       print "The SLC $parts[1] in the line $line in the TNC $_[0] is not in the right format\n";}
              $func_slc_map{$pieces[0]}{$pieces[1]}{$parts[1]}=$parts[0]; #create a hash of hashes of hashes, index1=node1,
index2=node2,index3=SLC, value=link
              $func_slc_map{$pieces[1]}{$pieces[0]}{$parts[1]}=$parts[0]; #create a hash of hashes of hashes, index1=node2,
index2=node1,index3=SLC, value=link
#we need both the above because either node can be OPC/DPC in the messages
           }
                                                                                                                                         110

    }
    return (\%func_valid_links,\%func_slc_map); #return the references to the hashes
}

######################################
#USAGE: %link_mapping=%{&get_link_mapping('lmf_file')};
#returns ref to hash of hash $link_mapping{machine_name}{monitor_name}='link dir'
#ex: $link_mapping{"NSTS1"}{"17T"}="C(246-242-000)(246-243-000)(0) 246-242-000" . meaning that the monitor 17T
# on the machine NSTS1 monitors the messages on the C(246-242-000)(246-243-000)(0) link going to 246-242-000

sub get_link_mapping{
   my ($line,@all_lines,@pieces,%func_link_map);
   open(MAP_FILE,$_[0])||die "Could not open the link mapping file $_[0]"; #open the LMF
   @all_lines=<MAP_FILE>; #read the file into an array
   close(MAP_FILE);
   foreach $line (@all_lines){ #for each line in the LMF
            unless($line=~/^\s*\Z/){
              chomp($line); #remove the \n
              @pieces=split(/\s+/,$line); #split the line around white space
              unless($valid_machine_name{$pieces[0]}){ #if the data for this machine is missing (no file with this name)
                       print "The data file $ARGV[0]_$pieces[0].out for the machine name $pieces[0] (as given in the lmf file) is
unavailable\n Possible mistake in the lmf file\n";}
              unless(($pieces[1]=~/^[\dabcdef]{2}[TC]\Z/)||($pieces[1]=~/^[\d]+\-[AB]\Z/)){ #if the monitor name is not a number
followed by T or C
                       print "The name of the monitor $pieces[1] in:\n $line\n in the lmf file is invalid. Right format ex:17T, 2eC, 2-A, 10-
B\n";}
              unless($valid_link_name{$pieces[2]}){ #if the link name is not present in the tnc file
                       print "The link $pieces[2] in the lmf file:\n$line\ncannot be found in the tnc file.\n";}
              unless($pieces[2]=~/$pieces[3]/){ #if the dir(end node) cannot be found in the link name
                       print "The link $pieces[2] is not connected to the node $pieces[3] in \n$line\n in the lmf file";}
              $func_link_map{$pieces[0]}{$pieces[1]}=$pieces[2]."\t".$pieces[3]; #create the hash entry. index1=machine_name,
index2=special_name, value = 'link dir'
            }
   }
   return \%func_link_map;
}

######################################
#usage $file_type = get_file_type(filename)
#returns the data type of the file. The file data is processed differently for different
#data types. This returned value is used as the data type identifier by these processing
#functions

sub get_file_type{                                      #find out the type of the data file
  my (@parts);
  @parts=split(/\./,$_[0]);          #split the file name around '.'
  return $file_extension_type{$parts[-1]}; #get the right data type from the table, -1 means the last value
}

######################################
#usage $machine_name = get_machine_name($file_name)
#the file name should be blahblah_MACHINE.extension - the function returns "MACHINE"

sub get_machine_name{
  my (@parts,@sub_parts);
  @parts=split(/_/,$_[0]); #split the file name around '_'
  @sub_parts = split(/\./,$parts[-1]); #split the last part around '.'
  return $sub_parts[0]; #the first piece is the machine name
}

######################################
#usage ($message_reference,$out_line)=read_message($file_handle,$file_type,$in_line);

#the function locates the first message in the file and returns the reference to the message to
#$message_reference and the first line of the next message to $out_line

sub read_message{
  my ($i,@func_message,$func_line,$func_file_type,$func_handle);
  $func_handle=$_[0];
  $func_file_type=$_[1];
                                                                                                                     111

    $func_line=$_[2];
    $i=0;                           #$i - line number of message
    $func_message[$i]=$message_separator;              #1st line is the separator
    if (($func_line=~/^d/)||($func_file_type eq 'EMR')){
              $i++;
              $func_message[$i]='MATCH_FLAG: 0'."\n"; #If it's a message (all EMRs), 2nd line is 0 match flag
    }
    elsif ($func_line=~/^m/){                #if it's a data measurement, match flag is 1
              $i++;
              $func_message[$i]='MATCH_FLAG: 0'."\n";
    }
    $i++;
    $func_message[$i]=$current_time{$func_handle}."\t $machine_name{$current_file}\n";
    if(message_begin($func_file_type,$func_line))              #if it is the beginning of message
    {
       $i=$i+1;
       $func_message[$i]=$func_line;                   #read the line into message
              $func_line=<$func_handle>;                     #read new line

      until(message_begin($func_file_type,$func_line)) #until beginning of the next message
      {
                $i=$i+1;
                $func_message[$i]=$func_line;                 #read the message
                $func_line = <$func_handle>;
                if (($func_file_type eq "STPLOG") && ($i == 3)){
                          $message_flag=1;                             #STPLOG messages have 2 lines and there are
                          #non-messages in the file.
#             last;
                }
                if (not($func_line)){                #if EOF then get out of loop
                          delete $current_time{$current_file};
                          print "\n\nFinished Reading: ",$file_name{$current_file},"\n\n";
                          last;
                }
      }
            if (($func_file_type eq "NSTS")|| ($func_file_type eq "EMR")){
                $message_flag=1;
            }
    }
    $i++;
    $func_message[$i]=$message_separator; #last line is the msg separator
    return (\@func_message, $func_line);
}

######################################
#usage message_begin($file_type,$line)

#returns 'TRUE' if $line is the first line of a message of the type given by $file_type

sub message_begin{
  if ($_[0] eq 'NSTS'){ return 1;}
  return ($_[1] =~ /^$msg_begin_string{$_[0]}/);
}

######################################
#usage $key = get_minimum(/%table);

#function returns the key corresponding to the minimum value of the table values.

sub get_minimum{
  my(%table,@keys);
  %table=reverse %{$_[0]}; #%table now has all values of the input as keys
  @keys=keys(%table); #get all the keys (input values)
  @keys= sort by_number @keys; #sort all the input values
  return $table{$keys[0]}; #return the wanted key
}

sub by_number{
  if ($a<$b){
           return -1;
                                                                                                                     112

    } elsif ($a==$b){
              return 0;
    } elsif ($a>$b){
              return 1;
    }
}


######################################
#usage standardize_pointcodes($file_type,\@message)
sub standardize_pointcodes{
  my ($message_line, $match,@id,$digit, $std_PC);

    if($_[0] eq "NSTS"){ #for NSTS verbose data
             foreach $message_line (@{$_[1]}){
                if($message_line=~/\d\d\d \d\d\d \d\d\d/){
                        $match=$&;
                        $old_match=$&;
                        $match=~s/\s/\-/g;
                        $message_line=~s/$old_match/$match/;
                }
             }
    }

    if ($_[0] eq "EMR"){ #for MGTS EMR data
              foreach $message_line (@{$_[1]}){
                 if ($message_line =~ /\d{1,3}-\d{1,3}-\d{1,3}/){ #locate the pointcode
                          @id = split(/-/,$&); #get each of the three numbers that make up the point code
                          foreach $digit (@id){ #foreach such number
                             if ($digit < 10) {$digit="00".$digit;} #if it's less than ten, add 2 zeros
                             elsif($digit < 100) {$digit = "0".$digit;} #else if it's less than 100, add one zero
                          }
                          $std_PC= join '-',@id; #join all three numbers with '-'
                          $message_line =~ s/$&/$std_PC/; #replace the point code with the standard one
                 }
              }
    }

    elsif ($_[0] eq "NSTSX"){
              foreach $message_line (@{$_[1]}){
                 if ($message_line =~ /^DPC: / or $message_line =~/^OPC: / #only OPC, DPC and APC have point codes
                          or $message_line =~/Affected Destination: /){
                          if ($message_line =~ /\d{1,3} \d{1,3} \d{1,3}/){ #same as above but without the '-'s
                             @id = split(/ /,$&);
                             foreach $digit (@id){
                                     if ($digit =~/\d+/){
                                        if ($digit < 10) {$digit="00".$digit;}
                                        elsif($digit < 100) {$digit = "0".$digit;}
                                     }
                             }
                             $std_PC= join '-',@id;
                             $message_line =~ s/$&/$std_PC\n/;
                          }
                 }
              }
    }
}

######################################
#USAGE: &standardize_link_names($file_type,$machine_name{$current_file},\@message);
#standardize the link names for events (substitute link and dir for the special link names used by NSTS and MGTS)
#for load measurement only: produce 2 formatted lines for loads in 2 dirs (NSTS data only).
#For EMR only: just add the word 'message' to the 4th line

sub standardize_link_names{
  my ($link,@params,$line,$c_load,$t_load,$load,$c_link,$t_link,$line_index);
  if ($_[0] eq 'NSTS'){ #If it is NSTS verbose
     if (${$_[2]}[3]=~s/^d/message/){ #replace the 'd' with 'message'
              $line_index=3; #the third line in the message has the parameters
              ${$_[2]}[$line_index]=~/[\dabcdef][\dabcdef][TC]/;
                                                                                                                                         113

          $link=$&; #the matched portion is the link's special name
          unless ( ${$_[2]}[$line_index]=~s/$link/$link_mapping{$_[1]}{$link}/ ){
                   print "Unknown link name in @message";}

        }
        elsif (${$_[2]}[3]=~/^m/){ #If it's a load measurement, the special link name is always the T one
           $line_index=3;
                 ${$_[2]}[$line_index]=~/[\dabcdef][\dabcdef][TC]/;
           $link=$&;
           chop($link); #get rid of the T
           ${$_[2]}[$line_index]=~s/C=.+//; #get rid of the load part
           $load=$&;             #save all that stuff in this
           $load=~s/C=\s*//;          #remove C=
           $load=~s/[^\/]+//;       #remove the C load
           $c_load = $&;          #save that load
           $load=~s/T=\s*//; #get rid of T=
           $load=$';
           $load=~/^[^\/]+/; #get rid of the value and /
           $t_load=$&; #the load is that part
           $t_link=$link.'T'; #special name of the 'T' link and dir
           $c_link=$link.'C'; #special name of the 'C' link and dir
           ${$_[2]}[$line_index]='load'."\t$link_mapping{$_[1]}{$t_link}\t$t_load\n";
           ${$_[2]}[$line_index+2]=${$_[2]}[$line_index+1];
           ${$_[2]}[$line_index+1]='load'."\t$link_mapping{$_[1]}{$c_link}\t$c_load\n";
           unless(($c_load=~/^[\d\.]+\Z/)&& ($t_load=~/^[\d\.]+\Z/)){
                          $filter_flag=0;}
    }
    }

    if ($_[0] eq 'EMR'){
       ${$_[2]}[3]="message\t".${$_[2]}[3];     }
}

######################################
#USAGE: $filter_flag = &filter_message(\@message, \%right_pointcodes);
#returns a 1 if the event is relevant, or returns 0 if it is not
# For all events, the filtering is done based upon the point codes that appear in the data
#for EMRs: filtering is also done on the EMR numbers. only numbers present in %emr_numbers are relevant

sub filter_message{
   my (@func_message, $msg_time,$temp_line, %func_PCs,$func_line);
   $PC_flag=1;
   @func_message = @{$_[0]}; #the event
   %func_PCs = %{$_[1]}; #the relevant pointcodes are the indices
   $message[2]=~/^[^\s]+/; #match the time(the first 'word' in the third line)
   $msg_time=$&; #matched part is the time
   if (($msg_time<$begin_time)||($msg_time>$end_time)){ #if the time is less than the test start time and greater than the test end time, it is
irrelevant
            return 0;}
   foreach $func_line (@func_message){ #foreach line in the event
            $temp_line=$func_line;
            while ($temp_line =~ /\d\d\d-\d\d\d-\d\d\d/){ #while there are pointcodes in the line, match the point code
               if(!($func_PCs{$&})) { #if the pointcode is not present in the pointcodes file
                        unless ($& eq '000-000-000'){ #and unless it is 000-000-000 (this sometimes appears in some messages)
                          $PC_flag=0;} #set the flag to 0
               }
               $temp_line=~s/$&//; #remove the point code from the line
            }
   }
   if ($func_message[3]=~ /EMR\#\s+\d+/){ #if it's an EMR
            $emr_num=$&; #get 'EMR' and the number
            $emr_num=~/\d+/; #find the number
            $emr_num=$&; #the matched part is the number
            unless($emr_numbers{$emr_num}){ #unless the EMR number is relevant, set the flag to 0
               $PC_flag=0;}
   }
   return $PC_flag;
}

######################################
                                                                                                                                    114

#usage $time_var = get_time(file_type,message_line,machine_name)
#for rta, the third argument is not needed
# returns the corrected time in seconds and original time stamp (separated by a tab)

sub get_time {
  @words=split(/\s+/,$_[1]);                    #split the line around
  $time_word = $words[$time_word_num{$_[0]}-1]; #get the time word
  @numbers=split(/:/,$time_word);                            #get the hr, min and sec
  $time_in_secs= 3600*$numbers[0]+60*$numbers[1]+$numbers[2];            #convert
  $time_in_secs += $clock_error{$_[2]};         #correct the time
  $two_time=$time_in_secs."\t".$time_word;    #append the original time stamp to it
  $_[1] =~ s/\Q$time_word/$two_time/;           #replace the time line with time in sec and original time
  return $two_time;

}

######################################
#USAGE: &format_message($file_type,$current_file,\@message,$machine_name{$current_file});}


sub format_message{
  my ($func_line,$line,$exp_link,$link);
  if($_[0] eq 'NSTS'){
           ${$_[2]}[3]=~s/\s*$current_time{$_[1]}//; #get rid of the time
           ${$_[2]}[3]=~s/\s*\dsls\d{3}//; #get rid of the sequence number
           if(${$_[2]}[3]=~/^message/){ #if it's a message
              chomp(${$_[2]}[3]);
       &replace_line(${$_[2]}[3],\@sorted_pointcodes,\%right_pointcodes);
              @params=split(/\s+/,${$_[2]}[3]); #split it around white space
              unless(@params>=6){ #there must be atleast 6 parameters
                      $filter_flag=0;} #if the message is like the SIO and SIOS, filter it out

       if($params[6]=~/L\d{1,2}/){          #change the slc (L0, L1 to link names)
                     $params[6]=$slc_mapping{$params[4]}{$params[5]}{$params[6]};
          if(@params==8){
                        if(($params[7]=~/lfsn/)||($params[7]=~/cbc/)){
                pop @params;} #get rid of lsfn(last parameter) in such messages
          }
       }
              $params[7]=~s/sts//; #the status, remove 'sts' from it

${$_[2]}[3]=$params[0]."\t".$params[1]."\t".$params[2]."\t".$params[5]."\t".$params[4]."\t".$params[3]."\t".$params[6]."\t".$params[7]."\t
".$params[8]."\n";          #rearrange the parameters to suit findmsg
              }
       if($unwanted_msg{$params[3]}){ $filter_flag=0;}
   }
           elsif ($_[0] eq "EMR"){
            ${$_[2]}[3]=~ s/ \d\d\/\d\d\/\d\d //;
            ${$_[2]}[3]=~s/\s*$current_time{$_[1]}//; #get rid of the time
      ${$_[2]}[3]=~s/EMR\#\s+\d+.+//; #remove the 'EMR' and the number
      $emr_num=$&;
      $emr_num=~/\d+/;
      $emr_num=$&;          #get the EMR number
      foreach $line (@{$_[2]}){ #for each line in the event
                if($line=~/LIC\s+\d+\-[AB]\s+PORT\s+\d+/){ #if the line has the LIC and PORT
                         $exp_link=$&;
                         $link=$exp_link;
                         $link=~s/LIC\s+//;
                         $link=~s/\s+PORT\s+\d+//;
                }     #get the special name of the link in $link. ex: LIC 1-A PORT 1 is converted to $link='1-A'
                if($line=~/Origination Point Code\s+/){
                         $opc=$'; chomp($opc);} #get the OPC of the message
                if($line=~/Destination Point Code\s+/){
                         $dpc=$'; chomp($dpc);} #get the DPC of the message
                if($line=~/Return cause/){ #if the line has a return cause (UDTS)
                         if($'=~/network congestion/){ #if the cause is network congestion
                            $cause='congestion'} #the casue is 'congestion'
                }
            }
      chomp(${$_[2]}[3]);
                                                                                                                                            115

        unless($link_mapping{$_[3]}{$link}){ #if the link is not wanted
                 $filter_flag=0;} #set the filter_flag to 0
        ${$_[2]}[3]=~s/\Q$exp_link/$link_mapping{$_[3]}{$link}/; #replace the special name with the link name
        ${$_[2]}[3]=${$_[2]}[3]."\t$opc"."\t$dpc"."\t$emr_numbers{$emr_num}";
        if($emr_numbers{$emr_num} eq 'UDTS'){
                 ${$_[2]}[3]=${$_[2]}[3]."\t$cause\n"; #if the message type is UDTS , add the cause as the last parameter
           @{$_[2]}=@{$_[2]}[0,1,2,3]; #remove all the lines after the fourth.
           ${$_[2]}[4]=$message_separator; #add the message separator as the last line
        }

    }

}


THE TRANSLATOR

#!/usr/local/bin/perl


#take care of the pause flag!!!!!!!!!!!!!!!!!

#INPUT FILES: exb, rta, tnc, paf
#OUTPUT FILES: specific analyzer (ex: test52_anz)

#we decide whether to process a line or not (based on '#', presence of a line number etc.) - in the main while loop, in get_labels and in
convert
$|=1;
use FindBin; #This and
use lib $FindBin::Bin; #this are used to tell the program that it should look for the libraries in the program's directory also

use replace_lib;
%loop_ender=();
@all_loop_ends=();
%loop_beginner=();
@all_loop_begins=();
%converted=();
$if_flag=0;
%known_labels=();
@action_labels=();
@links=();

%var_type=();
%var_list=();
%set_type=();
$errors=0;

%msg_param_type=(
          COO => first,
          COA => first,
          ECO => first,
          ECA => first,
          CBD => first,
          CBA => first,
         SLTM => first,
         SLTA => first,
          TFA => second,
          TCA => fourth,
          TFR => second,
          RSR => second,
          TCR => fourth,
          RCR => fourth,
          TFP => second,
          RSP => second,
          TCP => fourth,
          RCP => fourth,
          TFC => third,
          RCT => fifth,
          UDTS=> sixth,
                                                                                                                                       116

             SBR => seventh,
);
$label_flag=0; $label='';
$number_of_loop_begins=0;$number_of_loop_ends=0;
if($ARGV[0]=~/test5\d+b\Z/){
   $test_name=$ARGV[0];
   $test_name=~s/b\Z//;
   &replacer("$test_name.exb","mirror1","M$ARGV[0].exb");
   &replacer("M$ARGV[0].exb","mirror2","$ARGV[0].exb");
   unlink("M$ARGV[0].exb");
}
$out_file_name="../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/".$ARGV[0].".anz"; #the analyzer for this test


$hier =-1;       #the present level of hierarchy of 'if's. (we hacve nested if's)
$tree_hier=-1;     #This is for the filepointer and time handling of the data file in the _anz program
$wait_hier=-1;
@test_action_labels=(); #contains the labels of all test actions. used to find the next_test_step_time


if($ARGV[2]=~/tal/){
   do{
             $answer='y';
     if ($answer eq "y"){}
      elsif ($answer eq "n"){
                print "\nIf you already have a test action record for the test, then please give only one argument to the the program\n\n";
                exit;
             }
   }until (($answer eq "y")||($answer eq "n"));
}
%names_pointcodes = %{&get_symbol_hash("../../DATA/$ARGV[1]/$ARGV[0]/CONFIG/$ARGV[0].paf")}; #get the node_name - PC
table
   #keys contain the node names and the values are the pointcodes
%right_pointcodes = reverse %names_pointcodes; #has all the relevant PCs as the keys and the
#node names as values. Used for filtering.
@sorted_pointcodes=&sort_hash(\%right_pointcodes);


open(OUT_FILE, ">$out_file_name");#this is where the program output goes
open(MID_FILE, ">crystal_ball");#this file will be another perl program used to get the values of the labels used in the exb

print OUT_FILE "#!/usr/local/bin/perl\n\n";      #output is a perl program
print MID_FILE "#!/usr/local/bin/perl\n\n";      #the temp file is also a perl program

#$wait_hier=-1;

@links=@{&get_links("../../DATA/$ARGV[1]/$ARGV[0]/CONFIG/$ARGV[0].tnc")}; #get an array with values as valid links from the
_tnc file
if($ARGV[0]=~/test\d+a\Z/){
   $exb_name=$ARGV[0];
   $exb_name=~s/a\Z//;
   open(IN_FILE, "$exb_name.exb") || die "Cannot open file: $exb_name",'.exb';
}
else{
   open(IN_FILE, "$ARGV[0].exb") || die "Cannot open file: $ARGV[0]",'.exb';}
%set_type=%{&go_get_sets()}; #hash of set names and the corresponding type - 'link', 'node', and 'any'
close(IN_FILE);

if($ARGV[0]=~/test\d+a\Z/){
   $exb_name=$ARGV[0];
   $exb_name=~s/a\Z//;
   open(IN_FILE, "$exb_name.exb") || die "Cannot open file: $exb_name",'.exb';
}
else{
   open(IN_FILE, "$ARGV[0].exb") || die "Cannot open file: $ARGV[0]",'.exb';}
@labels=@{&get_labels()}; #get an array of all the labels used in the expected behavior and set the values of the labels for test actions
close(IN_FILE);

print OUT_FILE '$|=1;'."\n";
print OUT_FILE 'use FindBin qw($Bin);'."\n";
                                                                                                                              117

print OUT_FILE 'use lib "$Bin/../../../../BIN/analysis";'."\n";
print OUT_FILE 'use matching_lib ();'."\n";
print OUT_FILE '$time=0;',"\n"; #define a global variable $time
if ($^O =~ /Win32/){ #if its a windows system
   print OUT_FILE 'system ("copy","'."$ARGV[0]".'.aer", "'."$ARGV[0]".'.mer");'."\n";}
else { #If it's not windows, assume it is unix
   print OUT_FILE 'system ("cp","'."$ARGV[0]".'.aer", "'."$ARGV[0]".'.mer");'."\n";}
print OUT_FILE 'open(DATA_FILE,"+<',"$ARGV[0]",'.mer")||die "Could not open file:',"$ARGV[0]",'.mer";',"\n"; #open the data file +<
for both read and write without clearing the file
print OUT_FILE 'open(POL_FILE,">',"$ARGV[0]",'.pol");',"\n"; #open the parameter obs. list file for writing
#print OUT_FILE 'open(MER_FILE,">',"$ARGV[0]",'_mer");',"\n"; #open the matched event list file for writing
print OUT_FILE 'open(MEL_FILE,">',"$ARGV[0]",'.mel");',"\n"; #open the missing event list file for writing
print OUT_FILE 'open(HEL_FILE,">',"$ARGV[0]",'.hel");',"\n"; #open the hidden event list file for writing
print OUT_FILE 'open(XXB_FILE,">',"$ARGV[0]",'.xxb");',"\n"; #open the expanded expected behavior file

print OUT_FILE '%file_pointer_time=();',"\n"; #This table is used to remember the position of
#the file pointer for various times. This table is updated for every new time returned by
#a matched event. indices are times and values are the file pointer positions

print OUT_FILE '@monitored_links=&get_monitored_links();'."\n\n"; #hash containing links as indices and link dirs as values
print OUT_FILE 'print "Started Analyzing '.$ARGV[0].'\n";'."\n";

unless($ARGV[2]=~/tal/){

    if($ARGV[0]=~/test\d+a\Z/){
             $exb_name=$ARGV[0];
             $exb_name=~s/a\Z//;
             open(IN_FILE, "$exb_name.exb") || die "Cannot open file: $exb_name",'.exb';
    }
    else{
             open(IN_FILE, "$ARGV[0].exb") || die "Cannot open file: $ARGV[0]",'.exb';}
    while($line=<IN_FILE>){         #till the end of the file
             if($line =~ /^\d+/){    #if the line starts with #an integer
                unless($converted{$&}){ #if the not has not been converted
                         &convert();}      #convert it. 'convert' deals with the global variable $line and IN_FILE
             }
    }
    print "\n";
    close(IN_FILE);
}

print OUT_FILE 'print "\nThe MATCHED EVENT RECORD has been written to file:             '," $ARGV[0]",'.mer\n\n";',"\n";
print OUT_FILE 'print "The HIDDEN EVENT LIST has been written to file:           '," $ARGV[0]",'.hel\n\n";',"\n";
print OUT_FILE 'print "The MISSING EVENT LIST has been written to file:          '," $ARGV[0]",'.mel\n\n";',"\n";
print OUT_FILE 'print "The PARAMETER OBSERVATION LIST has been written to file:'," $ARGV[0]",'.pol\n\n";',"\n";
close(OUT_FILE);
if($ARGV[2]=~/tal/){unlink($out_file_name);} #If producing the
else{print "The analyzer for $ARGV[0] has been written to file: $out_file_name\n\n";}

if($ARGV[0]=~/test5\d+b\Z/){
   unlink("$ARGV[0].exb");}

####################################################################
sub get_links{
  my(@link_array);

    open(LINK_FILE,$_[0])||die "cannot open file: $_[0]"; #open the configurations file
    @link_array=<LINK_FILE>; #Each link is now an element of the array
    chomp(@link_array);
    close(LINK_FILE);
    return \@link_array; #return the reference to the array;
}
####################################################################
sub go_get_sets{
  my ($i,$j,$temp_index,$temp_name,$line,@terms,$output,@pieces,$piece,$set,%func_sets,$type_of_var,%elements);
  $i = 0;
  while($line=<IN_FILE>){            #till the end of the file
           if($line=~/^\s*[\$@]/){
              if ($line=~/^\s*\$/){
                        if($line=~/=\Z/){print "Error: line ends with a '=' in $line"; $errors++;}
                                                                                                              118


         @terms=split(/\s*=\s*/,$line);
         $terms[0]=~s/^\s*//; #get rid of leading white space
         unless ($terms[0]=~/^\$\w+\{.+\}\Z/){
           print "Left side of $line is not a valid reference to an array\n";$errors++;}
         $temp_index=$terms[0];
         $temp_index=~s/^\$\w+\{//; $temp_index=~s/\}\Z//; #get hold of the string inside {}
         unless((&token_type($temp_index) =~/node/)||(&token_type($temp_index)=~/link/)){
           print "Invalid index (inside {}) in $line\n"; $errors++;}
         $temp_name=$terms[0];
         $temp_name=~s/^\$//;
         $temp_name=~s/\{.+\}//;
         unless($temp_name=~/^\w+\Z/){
           print "Invalid name for a table $temp_name in: $line\n"; $errors++;}
         $output=$terms[0];
         $set='@{'.$terms[0].'}';

}
else { #($line=~s/^\s*@//){
         $line=~s/^\s*@//;
         if($line=~/=\Z/){print "Error: line ends with a '=' in $line"; $errors++;}

         @terms= split(/=/,$line);
         $terms[0]=~s/\s*\Z//;
         unless ($terms[0]=~/^\w+\Z/){
           print "Invalid name for a set in: $line\n"; $errors++;}
         $output='@'.$terms[0];
         $set='@'.$terms[0];
}
chomp($terms[1]);
if($terms[1]=~/^\s*\(\s*\)\s*;*\s*\Z/){
         $output=$output.'=();'."\n";
         if($func_sets{$set}){
            print "$set in $line has already been defined\n";}
         else{$func_sets{$set}='any';}

         print OUT_FILE $output;
         print MEL_FILE $output;
}
elsif ($terms[1]=~/^\s*\(.*\)/){
          $terms[1]=~s/^\(//;
          $output=$output.'='.'(';
          if($$terms[1]=~/,\Z/){print "Error: extra ',' in $line";$errors++;}
          @pieces=split(/,/,$terms[1]);
          if (&token_type($pieces[0])=~/node/){
             $type_of_var = 'node';}
          elsif (&token_type($pieces[0])=~/link/){
             $type_of_var = 'link';}
          else{
             $type_of_var = 0;
             print "$pieces[0] is not a node or a link in set definition: $line\n";
          }
          %elements=();
          if ($type_of_var){
             $j=0;
             foreach $piece (@pieces){
                      chomp($piece); #remove a possible \n
                      $piece=~s/^\s*//; #remove leading white space
                      $piece=~s/\s*\Z//; #remove trailing white space
                      if ($j+1==@pieces){$piece=~s/\s*\)?\s*\;*\Z//;} #remove ). ? is for 0 or 1 occurence;
                      if($elements{$piece}){print "$piece repeated in set deinition:\n$line";}
                      else{
                         $elements{$piece}=1;
                         $j++;
                         $output=$output.'"'.$piece.'",'; #add a comma next to it and use quotes
                         if (!(&token_type($piece)=~/\Q$type_of_var/)){
                                  print "$piece not a $type_of_var in set definition: $line\n"; $errors++;}
                      }
             }
             chop($output); #get rid of the last comma;
                                                                                                                                             119

                            $output = $output.');'."\n\n";
                            print OUT_FILE $output;
                            print MID_FILE $output;
                            if($func_sets{$set}){
                                     print "$set in $line has already been defined\n";}
                            else{$func_sets{$set}=$type_of_var;}
                        }
              }
              elsif($terms[1]=~/^\s*@.+/){
                        $terms[1]=~s/^\s*//; $terms[1]=~s/\s*\Z//;
                        unless ($func_sets{$terms[1]}){ print "RHS of the set def. in $line has not been defined\n";}
                        $output=$output.'='.$terms[1].";\n";
                        print OUT_FILE $output;
                        print MID_FILE $output;
                        if($func_sets{$set}){
                           print "$set in $line has already been defined\n";}
                        else{$func_sets{$set}=$func_sets{$terms[1]};}
              }
              else{print "Right side of set assignment is not a set in $line\n"; $errors++;}
             }
    }
    return \%func_sets;
}
####################################################################
sub get_labels{   #gets all labels, all action labels and a hash table with all action labels as indices
  my (@my_labels, $number,$a_label,$i,$event,$number_of_loops,$number_of_fors,@label_assigns,@run_command);
  $i = 0; $number_of_loops=0; $number_of_fors=0;

   unless($ARGV[2]=~/tal/){
             print MID_FILE "open(IN_FILE,","\"","../../DATA/$ARGV[1]/$ARGV[0]/TESTCASES/$ARGV[0]",'.rta',"\"",')|| die "Could
not open file:',"$ARGV[0]",".rta\";";
             print MID_FILE 'open(OUT_FILE,">the_vision");'."\n";
   }
   if($ARGV[2]=~/tal/){
             print MID_FILE '$write_tal=1;',"\n"; #if there is a second argument to translator, we write the test action list
             print MID_FILE 'open(TAL_FILE,',"\">../../DATA/$ARGV[1]/$ARGV[0]/TESTCASES/$ARGV[0]",'.tal");',"\n";
   }
   while($line=<IN_FILE>){                #till the end of the file
             $line=~s/\/\/MGTS//;
             if(($line =~/^\d+\.\s*/)&&!($line=~/REAL_SSPS/)){ #if the line starts with a number, get rid of it and white space
                $line =~s/^\d+\.\s*//;
                $number=line_number($&);
                if($line =~ /^\$.+\s*:/){ #and if the line has a word with a ':'
                          $a_label=$&;
                          $event=$';
                          chop($a_label);         #remove the ':' from the matched part
                          chomp($event);           #remove possible \n from the event
                          $event=~s/[^\)]+\Z//; #remove ; causes ...
                          $event=~s/^\s*//; #remove leading white space
                          $a_label=~s/\s*\Z//; #remove trailing spaceb
                          if(($event =~
/fail_link\(.+\)/)||($event=~/restore_link\(.+\)/)||($event=~/unblock_ssp\(.+\)/)||($event=~/block_ssp\(.+\)/)||($event=~/restart_stp\(.+\)/)||($ev
ent=~/test_end/)||($event=~/test_begin/)){
                             #if it is one of the test ations,
                             $a_label=~s/^\$//; #$sign needs to be removed because the program crystal_ball
                             #should not think that '$something' is a variable. We are interested in the
                             #word 'something'. crystal_ball should, in its output, print '$something=(the time)
                             print MID_FILE '&get_time("',$event,'"',',"',"$a_label",'");',"\n";
                             #the crystal_ball program should find the value of $a_label
                             $a_label="\$".$a_label;
                             $a_label=~s/\{\s*\$\w+\s*\}//; #get rid of any inside {$var}
                             $known_labels{$a_label}=1; #!!!!this should be changed to only action labels
                          }
#                         else{ print "Error in label assignment: $number. $line"; $errors++;}
                          $a_label=~s/\{\s*\$\w+\s*\}//; #get rid of any inside {$var}
                          $my_labels[$i]=$a_label; #the remaining part is a label

#             }
                          $i++;}
                                                                                                                                             120

                elsif(($line =~ /foreach/)||($line=~/while/)||($line=~/^\d+\.\s*\{\s*\Z/)){
                          $number_of_loops++;
                          if ($line=~ /foreach/){
                             $number_of_fors++;
                             chomp($line);
                             print MID_FILE $line."\n";
                          }
                }
                elsif($line =~/\}\s*\Z/){
                          if(($number_of_loops==$number_of_fors)&& !($number_of_fors==0)){ #we could have some extra }, so the 2nd
condition
                          chomp($line);
                          print MID_FILE $line."\n";
                          $number_of_loops--;
                          $number_of_fors--;
                       }
                       else{$number_of_loops--;}
                }
            }
   }
   print MID_FILE 'close(IN_FILE);',"\n";
   print MID_FILE 'close(OUT_FILE);',"\n";
#!!!!!! produce @action_labels and %known_labels
 #this contains the function that goes into the crystal_ball program
   $line=q{
sub get_time{

  if($write_tal){print TAL_FILE "\$$_[1]: $_[0] \n";}
  else{
           while($line=<IN_FILE>){ #should find events sequentially'
              if($line=~s/\s*\Q$_[0]\E.*\Z//){ # find and remove the action($_[0]) and succeeding text (causes etc)(notice .* not .+)
                       $line=~s/^\s*//; #get rid of leading white space
                       chomp($line); #this now has the time in hrs:min: and $label
                       @terms=split(/\s+/,$line); #1st term has time and 2nd term has the variable
                       $terms[1]=~s/\s*:\Z//; #get rid of white space and : after the label
                       unless ($terms[1] eq "\$".$_[1]){ #If this label is not the same as $second_argument
                          print "The variable names used are different $_[1] and $terms[1]\n";}
                       if($terms[1]=~/\{/){
                          @pieces=split(/\{/,$terms[1]);
                          $pieces[1]=~s/\}//;
                          $terms[1]=$pieces[0].'{"'.$pieces[1].'"}';
                       }

                       @pieces=split(/:/,$terms[0]); #$terms[0] has the time in hrs:min:sec.millisec format
                       unless(@pieces==3){             #if it is not in the above format
                          print "The time $line in line $. is not in the right format in the tar file \n";}
                       $time=$pieces[0]*3600+$pieces[1]*60+$pieces[2]; #calculate the time in sec.millisec
                       print OUT_FILE $terms[1],"=$time",";\n";             #print this info to the_vision file
                       return 1;                           #return
                }
            }

           die "$_[0] was not found in the tar file \n";        #if this was not found, then the file pointer is at the end of the file and no
further events can be found
   }
}
};
print MID_FILE $line;
close(MID_FILE);

@run_command=('perl','crystal_ball'); #the command to run the crystal_ball program ("perl crystal_ball")to obtain the label assignment
file(the_vision)
if(system @run_command){warn "unable to run the \"crystal_ball\" program to obtain the label assigments";}       #run the program
elsif($ARGV[2]=~/tal/){print "\nThe Test Action List has been written to file:$ARGV[0]","_tal\n\n";}


unlink("crystal_ball") or warn "Unable to delete the \"crstal_ball\" file"; #now delete the crystal_ball program
unless($ARGV[2]=~/tal/){
  open(LABEL_ASSIGN_FILE,"the_vision") or warn "Cannot open the label assigment file \"the_vision\"";
#open the file where crstal_ball put the output ($label1=time1 etc)
                                                                                                                   121

@label_assigns=<LABEL_ASSIGN_FILE>; #read all the assignments

foreach $label (@label_assigns){ #we know all the expanded test action label values ex: t_block{"246-242-000"}
   @pieces=split(/=/,$label);
   $known_labels{$pieces[0]}=1;
}
print OUT_FILE @label_assigns,"\n\n";     #write these assignments to the progperl file
$i=0;
foreach my $lab_assign (@label_assigns){
   @pieces=split(/=/,$lab_assign);
   $test_action_labels[$i]=$pieces[0];
   $i++;
}
@labels_with_commas=join(",",@test_action_labels);
print OUT_FILE '@test_action_labels=('."@labels_with_commas".');'."\n";

close(LABEL_ASSIGN_FILE); #close the "the_vision" file
unlink("the_vision") or warn "Unable to delete the \"the_vision\" file";
}
   return \@my_labels;
}


####################################################################
sub convert{
  my ($parent_number,$something,@pieces,$xlabel,$ylabel,$a_variable,$loop_type,$pause_flag,$wait_number);
  my (@children,$child,$number,$loop_number,$wait_patience,$wait_timer,$wait_node,@params,$event_type);
  my (@right_params,$while_time,$rem_fp);
  local (@event_params,@temp_params);

  if($errors>30){
           close(OUT_FILE);
           unlink($out_file_name);
           die "\n\n*************Total number of errors is more than $errors. Further processing aborted\n";}

  $line=~s/\/\/MGTS//;
  if(($line =~ /^\s*\#/)||($line =~ /^\s*\@/)){
            return 0;}        #stop if the line is a comment (starts with a '#')
  $line=~/^\d+/;
  if($converted{$&}){
            return 0;}
  if($line=~/\/\/REAL_SSPS/){ #if the line is for real_ssps only, don't process
            $line=~/^\d+/;
            $converted{$&}=1;
            return 0;
  }

  elsif(not($line =~ /^\s*\d+\.\s*[^\s\n]+/)){ #if the line is not 'integer. blah blah'
           unless($line=~/^\s*\Z/){      #unless the line is empty
              print "Error: Line should start with a '#' or a number, a '.' and a function : \n $line";
              $errors++;
              if ($line=~ /^\d+/){$converted{$&}=1;} #remember that this line has been dealt with
              return 0;
           }
  }

  $node_position[++$hier]=tell IN_FILE; #increment $hier and assign the new value.This is where should come back
  #in the expected behavior file
  #this is to take care of loops starting here or 'causes'
  if ($line =~ /:/){
            unless($line=~ /^\d+\./){
               print "\nSyntax error: line number should end with a '.' in $line\n"; $errors++;}
            $line =~ s/[^\.]+://; #match and remove the portion after number and '.' and ':'. This is the label
            $label=$&;            #get the matched portion
            chop($label);         #get rid of ':'
            $label=~s/^\s*//;      #get rid of leading white space
            $ylabel=$xlabel=$label; #make a copy of $label(which needs to be saved for later use)
            $xlabel=~s/^\$\w+\s*//;               #get rid of the initial $www and white space
            if($xlabel){         #if there is more of the label remaining. ex: $label{$a}. {$a} will remain
               $xlabel=~s/^\{//; #get rid of { and
                                                                                                                                         122

              $xlabel=~s/\}\s*\Z//; # } and whitespace
              unless ($var_type{$xlabel}){ #unless the variable is valid (used in a for loop)
                       print "\nSyntax error: $xlabel is not a valid label name in $line\n"; $errors++;}
           }
           $ylabel=~/^$\w+/; #get hold of the initial label name . ex: $label in $label{$a}
           if ($known_labels{$&}){ #if the label is already known(from the test action record)
              $action_flag=1; #label it as an action
              $action_label=$label; #the label name
           }
           else{
              $known_labels{$&}=1; #if the label is not known (not a test action)
              $label_flag=1; #it is just a label
           }
  }

  if ($line =~ /waitfor/){              #if the line has a 'waitfor'
            if ($line =~ /causes/){           #and if it has 'causes'
               if ($'=~/,\s*\Z/){print "Error: extra ',' in $line";$errors++;} #if the line ends with a ,
               @children = split(/,/,$');       #find out the numbers that it causes
               $line_old=$line;                #save the original line
               $line=~ s/cause.+\n//;           #remove "causes x,y..\n"
               $wait_number=line_number($line); #get the line number
               $converted{$wait_number}=1; #mark it as converted
               $line =~ s/^\d+.\s*waitfor\s*\(//;#remove " wait_for ("
                         $line =~ s/\)//;             #remove ")"
               if($line=~/,\s*\Z/){print "Error: extra ',' in $line";$errors++;} #if the waitfor has an extra ',' inside
               @params=split(/,/,$line);          #get the parameters
               @right_params=('timer','node','time'); #the right format is wait_for(T11,STPA)
               unless (token_compare(\@params,\@right_params)){ #&&(token($params[2],'patience')) #if the params are wrong
                         print "Syntax error: wait_for in line: $line_old usage: wait_for(timer,node) causes n1,n2 \n\n";
                         $errors++;
               }
               $params[3]=$wait_number;               #the line number of the wait_for (used to mark all observations caused by this
               #line in order to find out their minimum)
               $wait_hier++; #increase the waitfor hierarchy by 1
               print OUT_FILE '$waitfor_time['."$wait_hier".']=$time;'."\n"; #remember the present time. This will be passed into the
write_timer function. "$timer"="$time at which the message is found" - "$waitfor_timer[$..]"
               foreach $child (@children){ #for each of the children
                         $rem_fp=tell IN_FILE;            #remember the present position
                         chomp($child);               #remove a possible "\n" from the number
                         if(($child<=$wait_number)||($converted{$child})){ #if the child's number is less than its parent or if
                            # it has already been converted
                            print "Invalid 'waitfor' child $child at line $wait_number\n"; $errors++;
                         }
                         elsif ($child){ #if $child is a number
                            do{        #till the child is found
                                      unless($line=<IN_FILE>){          #if the file has ended
                                         die "Cannot find child $child of parent $parent_number"} #could also mean two parents for the child
                                      $number=line_number($line); #the number of the present line
                            } until ($number==$child);
                            chomp($line);
                            convert($line,\@params); #convert the child with @params.
                            #if @params is not a null, then a write_timer function is created with $line
                         }
                         seek IN_FILE,$rem_fp,0; #go back to where we started (at the waitfor)
               }
               $wait_hier--; #reduce the waitfor hierarchy by 1
            }
            else{      #if there is no 'causes' on the line
               print "'wait_for' appears without 'causes': $line"; $errors++;}
  }
  elsif($line =~ /causes/){ #if the line has causes
            if($'=~/,\Z/){print "Error: extra ',' in $line";$errors++;}
            @children=split(/,/,$');        #get the children
            $line =~ s/cause.+//;          #remove "casues x,y,..
            chomp($line);                #remove the possible \n
            $parent_number=line_number($line); #get the number fo the line
            $if_flag=1; #flag to indicate that the line to be converted has children (to put in 'if')
            $tree_hier++;
            convert($line,$_[1]);           #convert the line, the $_[1] is in case the parent of this line was a wait_for
                                                                                                                                        123

                        #$_[1] is \@params from above
         print OUT_FILE '$parent_time[',"$tree_hier",']=$time;',"\n";        #remember the time at the parent
         print OUT_FILE '$parent_fp[',"$tree_hier",']=tell DATA_FILE;',"\n"; #remember the file pointer at the parent
         foreach $child (@children){                     #assume that the numbers are listed in an ascending order
            $rem_fp=tell IN_FILE;
            chomp($child);                 #remove the possible \n
            if(($child<=$parent_number)||($converted{$child})){ #if the child is less than parent or has been converted
                     print "Invalid child $child at line $parent_number\n"; #could mean the child has more than one parent
                     $errros++;
            }
            elsif ($child){ #if $child is a number
                     do{
                         unless($line=<IN_FILE>){ #if it is EOF
                                  die "Cannot find child $child of parent $parent_number"}
                         $number=line_number($line); #get the line number
                     } until ($number==$child); #stop if the line is the child
                     print OUT_FILE '$time=$parent_time[',"$tree_hier",'];',"\n";       #go to the time at the parent
                     print OUT_FILE 'seek DATA_FILE,$parent_fp[',"$tree_hier",'],0;',"\n";          #go back to where you started in the file
                     convert($line);          #convert the child
            }
            seek IN_FILE,$rem_fp,0;
         }
         $tree_hier--; #we are out of the loop

         print OUT_FILE '}',"\n";            #complete the if statement with an }
}

elsif (($line =~ /while/)||($line=~/foreach/)||($line=~/^\d+\.\s*\{\s*\Z/)){ #if this is a loop. order is imp { should be last
          $number_of_loop_begins++;
          $loop_number=line_number($line); #get the line number

         if($line=~/foreach\s*/){            #the \s* is important to get rid of white space before $xxx
            $loop_type='foreach';
            $something=$';
            chomp($something);
            unless ($something=~/^\$\w+\s+\(.+\)\s*\{\s*\Z/){ #if it does not have the right structure
                     print "Syntax error in $line \n",' usage: foreach $var (@set) {',"\n"; $errors++;}
            @pieces=split(/\s+/,$something);
            if (not($pieces[0]=~/\$/)){
                     print "Syntax error: 'foreach' '$something[0]' is not a scalar variable in $line"; $errors++;}
            else{
                     unless($pieces[1]=~s/^\(\s*//){
                        print "Syntax error in $line \n",' usage: foreach $var (@set) {',"\n"; $errors++;}
                     unless ($pieces[1]=~s/\s*\).*//){
                        print "Syntax error in $line \n",' usage: foreach $var (@set) {',"\n"; $errors++;}
                     unless ($set_type{$pieces[1]}){
                        print "Error: The set $pieces[1] in $line is not defined\n"; $errors++;}
                     if($var_type{$pieces[0]}){
                        print "Error: Variable $pieces[0] already in use: $line"; $errors++;}
                     else{
                        $var_type{$pieces[0]}=$set_type{$pieces[1]}; #remember that it is a variable
                        $a_variable=$pieces[0];        #$a_variable is used to delete it from the table later at the end of the loop
                     }
            }
         }

         elsif ($line =~ /while/){
            $loop_type='while';
            $something=$'; #get everything to the right of while
            chomp($something); #remove \n
            if (not($something=~/^\s*\(.+\)\s*\{\s*\Z/)){ #if it is not (xxxx){
                      print "Syntax error in $line, usage: while($time<$expr) {\n"; $errors++;}
            elsif (not($'=~/^\s*\n*\Z/)){ #there should be no causes after {
                      print "Syntax error in $line Nothing should succeed '{' \n";$errors++;}
            $something =~ s/^\s*\(\s*//; #remove (
            $something =~ s/\s*\).+//; #remove ) and everything to the right of it
            if($something=~/<\Z/){print "Error: extra '<' in $line";$errors++;}
            @pieces=split(/</,$something); #split the inequality around <
            unless ($pieces[0]=~/^\s*\$time\s*/){ #the first piece should be $time
                      print "Syntax error in $line",'Usage: while($time<$expr) {',"\n\n";$errors++;}
                                                                                                                                               124

               unless (&token_type($pieces[1]) =~ /time/){ #the second piece should be a time
                        print "Syntax error in $line", 'usage: while($time<$expr) {',"\n";$errors++;}
               $while_time=$pieces[1];
           }

           unless($converted{$loop_number}){ #if not already converted
             $line=~s/^\s*\d+\.*\s*//;
             if($loop_type eq 'foreach'){
                      $tree_hier++;
                      print OUT_FILE '$parent_time[',"$tree_hier",']=$time;',"\n";       #remember the time at the parent
                      print OUT_FILE '$parent_fp[',"$tree_hier",']=tell DATA_FILE;',"\n"; #remember the file pointer at the parent
             }
             if($loop_type eq 'while'){
                      print OUT_FILE '$temp_action_time=$next_action_time;',"\n"; #the matching function try to find the event
                      print OUT_FILE '$next_action_time=',"$while_time",';',"\n"; #until $next_action_time. So, it has to be stored in a
variable($temp_...) and changed to the time in while condition
                      print OUT_FILE '$pre_while_time=$time;',"\n"; #store the time before entering the while loop
                      print OUT_FILE '$pre_while_fp=tell DATA_FILE;',"\n"; #store the file pointer position
                      print OUT_FILE '$while_flag=1;',"\n"; #set the while flag to 1 (to tell write_timer not to go back in time after
matching (write_timer goes back where it started otherwise))
                      print OUT_FILE '$find_flag=0;',"\n"; #find_flag is set to 1 if atleast one occurence of the event is found
             }
             print OUT_FILE $line."\n";
             if($loop_type eq 'while'){
                      print OUT_FILE 'if(eof DATA_FILE){last;}'."\n";} #if it's a while loop, get out of it if EOF is reached
           }

           $converted{$loop_number}=1;          #mark it as converted
           unless($line = <IN_FILE>){       #read the next line. if EOF
             die "Missing } in the loop $loop_number";} #print error msg
           $number=&line_number($line);        #get the line number
           $pause_flag=0; #set pause flag to 0

             do{
               if($number){ #if it's a valid line
                          unless($converted{$number}){         #if not converted
                             if(($line=~/pause/)||($line =~
/fail_link\(.+\)/)||($line=~/restore_link\(.+\)/)||($_line=~/unblock_ssp\(.+\)/)||($line=~/block_ssp\(.+\)/)||$line=~/restart_stp\(.+\)/||($line=~/te
st_end/)||($line=~/test_begin/)){$pause_flag=1;} #if the line is a pause or a test action, then set the flag
                             if(($_[1])&&($loop_type eq 'foreach')){ #if the foreach loop was caused by a wait_for, then pass the parameters
                                      &convert($line,$_[1]);}
                             else{&convert($line);}          #else, convert it. this could have children -> converting a whole bunch of things
                          }
               }
               else{
                          unless(($line =~/^\s*\Z/)||($line =~ /^\s*\@/)||($line=~/^\s*\#/)){
                             print "Error: Line should start with a '#' or a number: \n $line";
                             $errors++;
                          }
               }
               unless($line = <IN_FILE>){            #if EOF, print error msg
                          @all_loop_ends=keys %loop_ender;
                          foreach $key (keys %loop_beginner){
                             print "loop begins- $key ; loop ends- $loop_beginner{$key} \n";
                          }
                          print "Unable to find the end of loop starting at line $loop_number\n";
                          die "Missing } in a loop\n";
               }
               $number = &line_number($line); #get the number of current line, after conversion, the line number is lost.

          } until (($line =~/^\d+\.\s*\}\s*/) && !($loop_ender{$number}));#stop if the line is a } and it is not marked as a loop ender
#for some other loop. Loop ending line is a stand alone '}': ##. }
             $loop_beginner{$loop_number}=$number;

               if($loop_type eq 'foreach'){ #if it is a foreach loop and there are no pauses inside
                        unless($pause_flag){ #unless there is a pause in the loop
                          print OUT_FILE '$time=$parent_time[',"$tree_hier",'];',"\n";        #go to the time at the parent
                          print OUT_FILE 'seek DATA_FILE,$parent_fp[',"$tree_hier",'],0;',"\n";           #go back to where you started in the
file
                       }
                                                                                                                                          125

                        $tree_hier--;
               }
            &convert($line); #This is just }, so no need to position the fp(for loop)
            if ($loop_type eq 'while'){
               print OUT_FILE '$next_action_time=$temp_action_time;',"\n"; #change the next action time back
               print OUT_FILE '$time=$pre_while_time;',"\n";
               print OUT_FILE 'seek DATA_FILE,$pre_while_fp,0;',"\n"; #go back to the old position in the file
               print OUT_FILE '$while_flag=0;',"\n"; #unset the while flag
            }

      $loop_ender{$number}=1;            #mark it as a loop ender
           delete $var_type{$a_variable}; #if this is a for loop, the variable name is freed for reuse
           $number_of_loop_begins--;
           $number_of_loop_ends--;
  }


   elsif ($line=~s/\s*push\s*//){
             $number=&line_number($line); #get the line number
             chomp($line); #remove the \n
             $line=~s/^\d+\.*//; #remove the number and dot
             $line=~s/\s*;*\s*\Z//; #remove the nonsense at the end
             @pieces=split(/\s*,\s*/,$line);
             unless ($set_type{$pieces[0]}){
                print "The set $pieces[0] in the line $number. push $pieces[0],$pieces[1]\n"; $errors++;}
      unless (($pieces[1]=~s/shift\s*//)||($var_type{$pieces[1]})){
                print "PUSH needs to be used with shift or a loop variable in $number. push $pieces[0], $pieces[1]\n Usage: push \@set1,
shift \@set2 \n"; $errors++;}
             $pieces[1]=~s/\s*\Z//;
             unless ($set_type{$pieces[1]}){
                unless($pieces[1]=~/\$/){
                         print "The set $pieces[1] in the line $number".'.'." push $pieces[0], shift $pieces[1] has not been defined \n usage:
push \@set1, shift \@set2\n\n";
                         $errors++;
                }
             }
             unless($converted{$number}){
                if($pieces[1]=~/\$/){
                         print OUT_FILE "push $pieces[0],$pieces[1];\n";}
                else{
                         print OUT_FILE "push $pieces[0],shift $pieces[1];\n";}
                $converted{$number}=1;
             }
   }
   elsif ($line=~s/\s*shift\s*//){
             $number=&line_number($line); #get the line number
             chomp($line); #remove the \n
             $line=~s/^\d+\.*//;
             $line=~s/\s*;*\s*\Z//; #remove the nonsense at the end
             unless ($set_type{$line}){
                print "The set in the line $number".'.'." shift $line has not been defined \n usage: shift \@set\n\n";
                $errors++;
             }
             unless($converted{$number}){
                print OUT_FILE "shift $line;\n";
                $converted{$number}=1;
             }
   }
   else{        #no causes, no loops. so, only findmsg, assert_load,change, a test action,'}', and variable assignments
             $number=&line_number($line);
             $event_line=$line;
             if ($event_line=~s/.*change\s*\(//){ #get rid of "##. change ("
                $event_type="change";}
             elsif ($event_line=~s/.*findmsg\s*\(//){ #get rid of "##. findmsg ("
                $event_type="findmsg";}
             elsif ($event_line=~s/.*assert_load\s*\(//){ #get rid of "##. assert_load ("
                $event_type="assert_load";}
             elsif (($event_line =~
/fail_link\(.+\)/)||($event_line=~/restore_link\(.+\)/)||($event_line=~/unblock_ssp\(.+\)/)||($event_line=~/block_ssp\(.+\)/)||$event_line=~/res
tart_stp\(.+\)/||($event_line=~/test_end/)||($event_line=~/test_begin/)){
                                                                                                                          126

       $event_type="test_action";}
    elsif ($event_line=~/\}\s*\Z/){        #we can have } in change,wait_for, pause,....
       $event_type="loop_end";}
    elsif ($event_line=~/^\d+\.\s*\$/){
       $event_type='var_assign';}
    elsif ($event_line=~/pause/){
       $event_type='pause';}
    else{$event_type="invalid"; print "\nUnknown function in $line\n";$errors++;}

    chomp($event_line);           #event_line now has 'params)'
    $event_line=~s/\s*;*\s*\Z//; #get rid of ;
    $event_line=$event_line."\n"; #make sure the line has exactly one \n
    $event_line=~s/\)\s*\n//; #get rid of the trailing ")". This is now a list of parameters separated by commas
    if($event_line=~/,\Z/){print "Error: extra ',' in $line";$errors++;}
    @event_params=split(/,/,$event_line); #get the parameters of the event
    $change_flag=0;
    if ($event_type eq 'pause'){ #if it's a pause
       $number=&line_number($line); #get the line number
       chomp($line); #rid the \n
       $line =~s/^\d+\.*\s*pause\s*\(//; #get rid of everything until the parameter of pause
       $line=~s/\s*\);*//; #get rid of closing bracket. pause cannot cause anything
       @event_params=$line; #the parameter of pause
       @right_params='time'; #the parameter should be time
       unless (&token_compare(\@event_params,\@right_params)){ #check if the parameter is time
                print "Syntax error: pause in line: $line\n usage: pause(time)\n"; $errors++;}

        unless ($converted{$number}){
                 print OUT_FILE '$time='.$line.";\n"; #the time is now that specified in the pause
                 print OUT_FILE '&seek_fp($time);'."\n"; #move the file pointer to this time. is this needed???!!!
                 if($label_flag){ #if it's a normal label (not a test action which is already known)
                    print OUT_FILE "$label=",'$time',";\n"; #the value of the label is the present time
                    $label_flag=0; #unset the label flag
                 }
#                $converted{$number}=1; #line has been converted
        }
        $line="1";
        $event_type='pause';
    }
    if ($event_type eq "change"){ #if the event is a change
       @right_params=('time','time');
       @temp_params=@event_params[0,1];
       unless(token_compare(\@temp_params,\@right_params)){ #the first two params should be times
                print "Syntax error in $line First two parameters should be times.\n\n";$errors++;}

        shift @event_params; shift @event_params; #remove the first two params
        if($event_params[0]=~/findmsg/){$event_type='findmsg'; shift @event_params;} #
        if($event_params[0]=~/assert_load/){$event_type='assert_load';shift @event_params;}
        $change_flag=1;
    }

    if ($event_type eq "findmsg"){ #if the event is a findmsg
       $event_params[4]=~s/^\s*//;
       $event_params[4]=~s/\s*\Z//; #this holds the message type
       if(($event_params[2]=~/@/)||($event_params[3]=~/@/)){
                $event_params[2]=~s/^\s*//; $event_params[2]=~s/\s*\Z//; #get rid of white space
                $event_params[3]=~s/^\s*//; $event_params[3]=~s/\s*\Z//; #get rid of white space
                unless($set_type{$event_params[2]} eq 'node'){
                   print "Error: The first set $event_params[2] in the findmsg:\n$line\n is not of the right type\n";}
                unless($set_type{$event_params[3]} eq 'node'){
                   print "Error: The second set $event_params[3] in the findmsg:\n$line\n is not of the right type\n";}
                if($event_params[2] eq $event_params[3]){
                   print "Error: Both the sets used in \n$line are the same\n";}
       }

        if ($msg_param_type{$event_params[4]} eq 'first'){
                @right_params=('link','node','node','node','msg','link');} #define the syntax of findmsg
        elsif($msg_param_type{$event_params[4]} eq 'second'){
                @right_params=('link','node','node','node','msg','node');} #define the syntax of findmsg
        elsif($msg_param_type{$event_params[4]} eq 'third'){
                @right_params=('link','node','node','node','msg','node','status');} #define the syntax of findmsg
                                                                                                                                           127

               elsif($msg_param_type{$event_params[4]} eq 'fourth'){
                        @right_params=('link','node','node','node','msg','cluster');} #define the syntax of findmsg
               elsif($msg_param_type{$event_params[4]} eq 'fifth'){
                        @right_params=('link','node','node','node','msg');} #define the syntax of findmsg
               elsif($msg_param_type{$event_params[4]} eq 'sixth'){
                        @right_params=('link','node','node','node','msg','cause');} #define the syntax of findmsg
               elsif($msg_param_type{$event_params[4]} eq 'seventh'){
                        @right_params=('link','node','node','node','msg','node','number','number');}
               elsif($event_params[4] eq '*'){              #wild card is allowed
                        @right_params=('link','node','node','node','true');
               }
               else{ print "unknown message type $event_params[4] in line: $line\n";$errors++;}
               if (@right_params>3){
                        unless(token_compare(\@event_params,\@right_params)){ #if the syntax is wrong
                           print "Syntax error in $line\nright usage: findmsg(link,dest,OPC,DPC,msg_type,...)\n\n";$errors++;}
               }
           }

           elsif($event_type eq 'assert_load'){
              if (@event_params == 3){
                       @right_params=('link','node','load');}
#             elsif (@event_params == 4){
#                      @right_params=('link','node','load','traffic_type');}
              else {print "Syntax error: wrong number of parameters in $line\n";}
              unless(token_compare(\@event_params,\@right_params)){ #if the syntax is wrong
                       print "Syntax error in $line\nright usage: assert_load(link,dest,load)\n\n";$errors++;}
           }

           elsif($event_type eq 'var_assign'){
              $event_line=~s/^\d+\.\s*//;
              $event_line=~s/\s*\Z//; #remove the ; and white space at the end
              @pieces=split(/=/,$event_line);
              unless($pieces[0]=~/^\$.+/){
                       print "The variable name $pieces[0] used in line $line is invalid\n"; $errors++;}
              $var_list{$&}=1; #maintain a list of all variables used
              @pieces=split(/[\+\-]/,$pieces[1]);
              foreach $piece (@pieces){
                       $piece=~s/^\s*//; $piece=~s/\s*\Z//;
                        unless(($piece=~/^[\d\.]+\Z/)||$var_list{$piece}){
                          print "The variable assignment $pieces[1] in $line is invalid.\n"; $errors++;}
              }
           }

           $event_line=join(",",@event_params); #The white space is removed from the params, they have "" around them
           if ($_[1]){      #if this line was caused by a wait_for
              chomp($line); #remove a possible \n
              @timer_params=@{$_[1]}; #get the parameters into
              if($change_flag){$event_type='change';} #if it was a change msg, event is 'change', needed as it was changed to findmsg or
assert_load

$line="\&write_timer($timer_params[3],".'$waitfor_time['."$wait_hier".'],'.$timer_params[0].",".$timer_params[1].',"'.$event_type.'",'."$nu
mber,".$event_line.")";
             #convert this to a write_timer function:
write_timer($waitfor_time,waitforline_number,T11,STPA,findmsg,line_no,link,node,....)
           }

           unless ($converted{$number}){ #if it was not already converted
             chomp($line);
             $line=~s/^\s*\d+\.*\s*//; #remove the line number
             unless($_[1]||($event_type eq 'test_action')){$line=~s/\)[^\)]*\Z//;} #get rid of the last ), if it's not a writetimer
             if($event_type eq 'test_action'){    #if it is a test action
                      $line=~s/^\s*//;$line=~s/\s*;*\Z//; #remove whitespace
                      $line='&test_action('."$number,\"".$line.'")'; # it is passed as the parameter to the test_action func.notice the quotes

               }
               if ($event_type eq 'loop_end'){ #if it's a }
                        $number_of_loop_ends++;          #increase the numb. of loop_ends
                        if($number_of_loop_ends>$number_of_loop_begins){
                           @all_loop_ends=keys %loop_ender;
                           @all_loop_ends=sort @all_loop_ends;
                                                                                                                                         128

                           foreach $key (@all_loop_ends){
                                     print "loop begins- $loop_beginner{$key} ; loop ends- $key \n";
                           }
                           die "\nAn extra } present somewhere in the exb file. error found at line $number\n";} #if it is more than the number
of loop_begins, it is an error
               }
               unless (($event_type eq 'loop_end')||($event_type eq 'var_assign')){ #if it is not a loopend
                        unless(($_[1])||($event_type eq 'test_action')){      #if it is not a write_timer or a test action
                           if($event_type eq 'pause'){
                                     $line="1";}
                           else{
                                     $line='&'.$event_type.'('."$number,".$event_line.')';} #pass the line number as the first parameter and
all the other parameters. notice the &
                        }
                        if ($if_flag){           #if this line has children
                           $line = "if (".$line.') {'."\n".'$parent='."$number;"; #convert this to an if condition
                           unless($event_type eq 'assert_load'){$if_flag=0;}
                        }
                        else{
                           $line=$line.';';} #If there is no 'if' around it, append a ';'
               }
               if ($event_type eq 'var_assign'){
                        $line=~s/;//;
                        $line=$line.';';
               }
               unless($event_type eq 'invalid'){
                        if($event_type eq 'assert_load'){
                           print OUT_FILE '$pre_load_time=$time;',"\n"; #if it's assert load, go back to the old time
                           print OUT_FILE '$pre_load_fp=tell DATA_FILE;',"\n"; #and fp position
                        }
                        print OUT_FILE $line,"\n";
                        if($event_type eq 'assert_load'){
                           if($if_flag){$if_flag=0;} #!!!!
                           else{
                                     print OUT_FILE '$time=$pre_load_time;',"\n"; #go back
                                     print OUT_FILE 'seek DATA_FILE,$pre_load_fp,0;',"\n";
                           }
                        }
               }
               if(($event_type eq 'test_action')&&!($line=~/pause/)){
                        print OUT_FILE '$new_action_time=shift @test_action_labels;'."\n"; #get the next action time
                        print OUT_FILE 'if($new_action_time == $old_action_time){'."\n".'print "\n\nWARNING: the test action time
$new_action_time is same as the time of the previous test action\n\n\n";}'."\n";
                        print OUT_FILE '$next_action_time=$test_action_labels[0];'."\n";
               }
               if($label_flag){
                        print OUT_FILE "$label=",'$time',";\n"; #if it's a normal label, set the label value
                        $label_flag=0;
               }
               if($action_flag){
                        print OUT_FILE '$time=',"$action_label;\n"; #if it's a test action, set the time
                        print OUT_FILE '&seek_fp($time);',"\n"; #and go to the right file pointer position
                        print OUT_FILE '$old_action_time=$time;'."\n";
                        $action_flag=0;
               }
               $converted{$number}=1;
            }
   seek IN_FILE,$node_position[$hier--],0;            #go back to where you started in the file
   }
}


####################################################################
#usage token_compare(\@array1,\@array2)
#checks if the type of the elements in argument 1 are the same as the
#corresponding element in argument2.
#returns 1 if all the types match returns 0 if not.

sub token_compare{
  my ($i,@param,@param_type,$truth,$actual_type);
                                                                                                                                           129

# @param=@{$_[0]};
  @param_type=@{$_[1]};

    unless(@{$_[0]} == @param_type){
             print "\nError: wrong number of parameters(check for extra ',') in $line";
             $errors++;
    }
    $truth=1;
    for ($i=0;$i<@{$_[0]};++$i){ #for each of the parameters
             ${$_[0]}[$i]=~s/^\s*//; #remove leading white space
       ${$_[0]}[$i]=~s/\s*\Z//; #remove trailing white space

      unless (${$_[0]}[$i] =~ /^\s*\*\s*\Z/){       #if it is a wild card, always true
        $actual_type=&token_type(${$_[0]}[$i]);
        if (!($actual_type=~/\Q$param_type[$i]/ )&& ($actual_type ne 'any') ){ #if it is of the wrong type
                        print "${$_[0]}[$i] is not a $param_type[$i] $actual_type\n";
                        $truth=0;
                }
      }
      unless($param_type[$i] eq 'load'){
        ${$_[0]}[$i]='"'.${$_[0]}[$i].'"';}
     }
    return $truth;
}

#####################################################################
#usage token_type($token)
#finds out the token type of the argument
#returns the token type. valid token types: 'timer','node','msg','link'

sub token_type{
  my ($something,$link,$piece,@pieces,$link_flag,$load_flag,$time_flag,$inner);

    $something=$_[0];
    $something =~ s/^\s*//;           #remove leading white space
    $something =~ s/\s*\Z//;          #remove trailing white space

    if ($something=~ /T\d+/){          #if it is "T##" (where # is a digit)
            return 'timer';}           #it's a timer

    elsif ($msg_param_type{$something}){       #if the argument is an entry in the messages table
             return 'msg';}         #it's a message

    elsif ($something=~ /^[ABCDE]/){             #if it starts with an A,C,D or E
              for($i=0;$i<2;$i++){              #we could have two variables, so do it twice
                 if($something=~/\$\w+/){            #incase there is a variable
                           if (($var_type{$&} eq 'node')||($var_type{$&} eq 'any')){     #make sure the variable occurs ina foreach loop
                              $something=~s/\(\s*\$\w+\s*\)//;} #and remove the '( $xx ). Only one variable in a link.
                 }
              }
              if ($something=~/^[ABCDE]\Z/){          #if the parameter is just an A,C,D or E, it's a link
                 return 'link'}

             if($something=~/\(\Z/){print "Error: extra '(' in $line";$errors++;}
             @pieces=split(/\(/,$something);      #split the word around (, we get STPA), SSP2), 0) etc.

             if (@pieces<=4){                #C(STPA)(STPB)(0) -> four pieces
                foreach $link (@links){           #foreach link from the config. file
                        $link_flag=1;
                        unless ($link=~/^\Q$pieces[0]/){ #A and C can appear in STPA and STPC. so ^ is needed
                           $link_flag=0;}
                        foreach $piece (@pieces[1,2]){        #foreach piece
                           unless ($link=~/\Q$piece/){ #try to find the piece in the link
                                    $link_flag=0;}         #unset the link_flag if we can't find it
                        }
                        if ($link_flag==1){last;}       #break if we find a match
                }
                        if (@pieces==4){
                           unless($pieces[3]=~/^[01]\)\Z/){ #the third piece should be a 0 or a 1
                                    $link_flag=0;}
                                                                                                                              130

                            }
                            if ($link_flag){return 'link';} #it's a link if all pieces match
                 }

    }

    elsif ($names_pointcodes{$something}){ #if it's found in the pointcodes file, it's a node or a cluster
             return 'cluster node';}
#    elsif ($something=~/^\d\d\d-\d\d\d-\d\d\d\Z/){ #if it is "###-###-###", it's a node
#            if($something=~/000\Z/){
#               return 'cluster node';}
#            else{return 'node';}
#    }

    elsif($var_type{$something} eq 'any'){
             return 'any';}

    elsif($var_type{$something} eq 'node'){            #if it is a node variable
             return 'node';}

  elsif($set_type{$something} eq 'node'){        #if it is a set of nodes
           return 'node';}
  elsif($something=~/^[0123]\Z/){
#          if($something<=1){
              return 'status or load or number';#} #if it's less than or equal to 1, it could be load also
#          else{return 'status';}
  }
  elsif($something=~/congestion/){
           return 'cause';}
  else{
           $time_flag=1;
           $load_flag=1;
           if($something=~/\[\+\-]\Z/){print "Error: extra '+' or '-' in $line";$errors++;}
           if($known_labels{$something}){
              return 'time';}

                 @pieces = split(/\s*[\+\-]\s*/,$something);
                 if (@pieces){                     #we need to look at pieces because the order of the nodes could be
                                      # different from that in the test configuration file ex: A(STPA)(SSP1), A(SSP1)(STPA)
                    foreach $piece (@pieces) {
                              if ($piece =~ s/\{.+\}//){
                                 $inner = $&;
                                 $inner=~s/\{//; $inner=~s/\}//;
                                 unless ($var_type{$inner}){
                                          print "$inner in $something is not a variable in $line\n";}
                                 unless (($piece=~/^[\d\.]+\Z/)||($var_list{$piece})){
                                          $load_flag=0;}
                                 unless (($piece=~/^[\d\.]+\Z/)||($known_labels{$piece})){
                                          $time_flag=0;}
                              }
                    }
                    if($load_flag&&$time_flag){return 'load or time or number';}
                    if($load_flag){return 'load or number';}
                    elsif ($time_flag){return 'time or number';}
                 }
    }
    return '';
}
#####################################################################
#usage line_number($line)
#finds out the number of the line in the exp. behavior file
#returns the number if the line starts with a number(not even
#white space allowed before the number)
#returns null if the line doesn't start with a number

sub        line_number{
  my ($some_number);
  if($_[0]=~/^\d+/){
           $some_number = $&;}
  return $some_number;
                                                                                                                                          131

}
#####################################################################


MATCHING LIBRARY

#!/usr/local/bin/perl

$accuracy=0.20; #accuracy is 20%
$patience=5;

%msg_param_type=(
           COO => first,
           COA => first,
           ECO => first,
           ECA => first,
           CBD => first,
           CBA => first,
           TFA => second,
           TCA => second,
           TFR => second,
           TCR => second,
           RSR => second,
           RCR => second,
           TFP => second,
           RSP => second,
           TFC => third,
           RCT => third,
);
%type_params=(
          first => ['link','dir','opc','dpc','msg_type','slc'],
          second => ['link','dir','opc','dpc','msg_type','dest'],
          third => ['link','dir','opc','dpc','msg_type','dest','status'],
          fourth => ['link','dir','opc','dpc','msg_type'],
);

$message_separator ="+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
$line=''; #this is a global variable (???)
$no_read=0;
$no_find_read=0; $extra_read=0;

sub get_monitored_links{
  my (@fun_links,$begin_fp,$line);
  $begin_fp=tell DATA_FILE;
  unless($line=<DATA_FILE>){die "THE ACTUAL EVENT RECORD IS EMPTY"};
  while($line ne $message_separator){
           unless($line=~s/^link\s*//){ "The AER file is in the wrong format line number $.: $line The list of monitored links could be
missing in the file- check the lmf file";}
           chomp($line);
           @pieces=split(/\s+/,$line);
           $line=$pieces[0]."\t".$pieces[1];
           unshift @func_links,$line; #array with linkname and link dir
           $line=<DATA_FILE>;
  }
  seek DATA_FILE,$begin_fp,0;
  return (@func_links);
}

sub test_action{
  print "Test Action @_\n";
  print MEL_FILE "Test Action - @_ TIME: $test_action_labels[0]\n";
  print HEL_FILE "Test Action - @_ TIME: $test_action_labels[0]\n";
  print POL_FILE "Test Action - @_ TIME: $test_action_labels[0]\n";
  print XXB_FILE "TEST ACTION - @_ TIME: $test_action_labels[0]\n";
  return 1;
}

sub findmsg{
                                                                                                                                 132

   my
($start_time,$start_fp,$match_flag,$string1,$string2,$link_flag,@message_params,$line_number,@wanted_params,@wanted_values,$for_
xxb,$wildcard_flag);
   local (@message,$match_flag_fp,$message_end_fp); #@message holds a complete message, last line has the message separator. This
array is processed by all the functions called by findmsg
   unless($number_while){$number_while=0;}
   $line_number=$_[0]; #get the line number in the exb. used in the mel file
# @wanted_params=@{$type_params{$msg_param_type{$_[5]}}}; #get the parameter types from the message type
   $start_time=$time; #remember when we started.
   $start_fp=tell DATA_FILE;
   @wanted_values=@_; #looking for these values of the parameters
   shift @wanted_values; #get rid of the line number
   $wildcard_flag=0;
   $for_xxb=join(",",@wanted_values);
   if($for_xxb=~/\*/){
            $wildcard_flag=1;}
   unless($while_flag){
            print XXB_FILE "$line_number. findmsg($for_xxb)";}
   $wanted_link=shift(@wanted_values);
   @pieces=split(/\(/,$wanted_link);
# $no_read=0; #number of unsuccessful messages read before the match
# unless(($wanted_link=~/\Q$wanted_values[0]/)||($wanted_values[0] eq '*')){ #if the dir. node is wrong, die
#           die "The direction node given in $line_number. FINDMSG($wanted_link,@wanted_values)\n is not connected to the link";}
   unless($wanted_link eq '*'){
            unless(&valid_link($wanted_link,$wanted_values[0])){
               print HEL_FILE "$line_number. findmsg($for_xxb)\n";
               unless($while_flag){
                          print "DATA NOT AVAILABLE: \"FINDMSG @_\"\n";
                          print XXB_FILE "HIDDEN\n";
                          return 2;}
               print XXB_FILE "$line_number. findmsg($for_xxb)HIDDEN\n";
               last; #if in a while loop, get out
#              return 0;
            }
   }
   unless(eof DATA_FILE){ #unless it the end of the data file
            do{
               @message='';
               &read_msg;          #read a message
               $no_read++;
               if((@message==4)&&!($message[0]=~/^MATCH_FLAG: 1/)){ #4 lines in messages and 5 lines in load measurements
                          $time=&msg_time($message[1]); #get the time
                          if(($time>=$start_time)&&($time<$next_action_time)){ #if this time is less than that of the next test action
                             @message_params=@{&get_params($message[2],'message')}; #the 3rd line in the message should have 'message'
                             $message_link=shift(@message_params); #get the link in the message(1st param)
                             if($wanted_link eq '*'){$message_link='*';} #take care of wildcards
                             if($wanted_values[3] eq '*'){
                                      @message_params=@message_params[0,1,2,3];}
                             for ($i=0;$i<=$#wanted_values;$i++){ #wildcards
                                      if($wanted_values[$i] eq '*'){
                                         $message_params[$i]='*';}
                             }
                             $link_flag=1; #The flag is 1 if the wanted link is found
                             if(@pieces==4){ #If the number of pieces is 4, we have (0) or (1)
                                      $slc=pop @pieces; #get the 0) or 1) into $slc and remove it from @pieces
                                      unless($message_link=~/\Q$slc\E\Z/){ #unless we see $slc at the end of the link name
                                         $link_flag=0;} #unset the link flag
                             }
                             foreach $piece (@pieces){ #foreach of the rest of the pieces
                                      unless($message_link=~/\Q$piece/){ #unless the piece is seen in the link name
                                         $link_flag=0;} #unset the flag
                             }

                       if($link_flag){ #if the link is OK
                                $string1=join("",@message_params); #combine all of the other message parameters found
                                $string2=join("",@wanted_values); #combine all of the other wanted parameter values
                                if($string1 eq $string2){ #if these strings are the same
#                                  unless($while_flag){print "MESSAGE FOUND-LINE $line_number TIME:$time\n";} #then we have a
match
                                  #getc; #wait till the user hits a key
                                                                                                                                    133

                                        seek DATA_FILE,$match_flag_fp,0; #go to where the flag is
                                        if($wildcard_flag){
                                                 print DATA_FILE "MATCH_FLAG: *";} #set the flag
                                        else{
                                                 print DATA_FILE "MATCH_FLAG: 1";} #set the flag
                                        seek DATA_FILE,$message_end_fp,0; #go to the end of message
                                        unless ($find_flag&&$while_flag){
                                                 unless($while_flag){
                                                    print "FOUND: \"FINDMSG @_\ $time\"\n";
                                                    print XXB_FILE "FOUND\n";
                                                 }
                                        }
                                        if(($find_flag==0)&&($while_flag)){
#                                                print "MESSAGES FOUND IN WHILE LOOP-LINE:$line_number START TIME:$time\n";
                                                 $find_flag=1;}
#                                       print "FINDMSG : NO_READ = $no_read\n";
                                        if($while_flag){ $no_find_read=$no_read; $number_while=$number_while+1;}
                                        return 1; #say that we found it
                                    }
                          }
                        }
               }
            }until (($time>=$next_action_time)||(eof DATA_FILE)); #try tofind the message until the time of the next message or until the
end of the file
   }
   if($while_flag){
            print XXB_FILE "$line_number. findmsg($for_xxb)WHILE:$number_while ";
#           unless($find_flag){print MEL_FILE "$line_number. findmsg($for_xxb)\tparent: $parent\n";} #if not found, print to the MEL
file
   }
   unless($while_flag&&$find_flag){
            print "NOT FOUND- \"FINDMSG @_\"\n";
            print MEL_FILE "$line_number. findmsg($for_xxb)\tparent: $parent\n"; #if not found, print to the MEL file
            print XXB_FILE "NOT FOUND\n";
   }
   if($while_flag&&$find_flag){
            print "WHILE LOOP: FOUND $number_while MESSAGES \"FINDMSG @_\"\n";
            print XXB_FILE "FOUND\n";
            $extra_read=$extra_read+$no_read-$no_find_read;
            $number_while=0;
   }
# print "NOT FINDMSG: NO_READ = $no_read\n";
# print "WHILE EXTRA: $extra_read\n";


  unless($while_flag){
          seek DATA_FILE,$start_fp,0; #unless in a while loop, go back to starting poin if messge not found
          $time=$start_time;
  }
# print "NOT FOUND \"FINDMSG @_\"\n";
# unless($stop_flag){
#         if(getc=~/q/){$stop_flag=1;}}

    return 3; #if not found, return a 0. CHANGE THIS BACK TO '0'. !!!!
#    return 0;
}

sub assert_load{
   my
($func_pre_fp,$func_pre_time,$func_link,$func_line_numb,$i,$start_time,$line_number,@load_params,@pieces,$obs_values,$load_diff,$
message_link,$piece,$link_flag,@wanted_params,@wanted_values,$load_found_flag);
   $start_time=$time;
   @wanted_values=@_; #looking for these values of the parameters
   $line_number=shift @wanted_values; #get the line number in the exb. used in the mel file
   $wanted_link=shift @wanted_values; #wanted_valkues now has the dir and the load
   @pieces=split(/\(/,$wanted_link);
# $no_read=0;

    $load_found_flag=0;
     unless($wanted_link eq '*'){
                                                                                                                                    134

           unless(&valid_link($wanted_link,$wanted_values[0])){
             print XXB_FILE "$line_number. assert_load($for_xxb)HIDDEN\n";
             print HEL_FILE "$line_number. assert_load($for_xxb)\n";
             unless($while_flag){
                        print "DATA NOT AVAILABLE: \"ASSERT_LOAD @_\"\n";
                        return 2;}
             last; #if in a while loop, get out
           }
   }
  if(($wanted_values[1]>100)||($wanted_values[1]<0)){
            die "The load used in assert_load in line:$line_number, $wanted_link $wanted_values[0] LOAD: $wanted_values[1] is not in
the range 0 to 100\n";
   }
   unless($wanted_link=~/\Q$wanted_values[0]/){ #if the dir. node is wrong, die
            die "The direction node given in $line_number. FINDMSG($wanted_link,@wanted_values)\n is not connected to the link";}
   $for_xxb=join(",",$wanted_link,@wanted_values);
   if(@pieces==3){
            $func_pre_fp=tell DATA_FILE;
            $func_pre_time=$time;
            $func_link=$_[1]."(0)";
            $func_line_numb=shift @_;
            shift @_;
            if(&assert_load($func_line_numb,$func_link,@_)){
               $func_success_one=1;}
            else{$func_success_one=0;}
            seek DATA_FILE,$func_pre_fp,0;
            $time=$func_pre_time;
            $func_link=~s/\(0\)/\(1\)/;
            if(&assert_load($func_line_numb,$func_link,@_)){
               $func_success_two=1;}
            else{$func_success_two=0;}
            if($func_success_one&&$func_success_two){
               return 1;}
            else{return 0;}
   }
# @wanted_params=['link','dir','load'];
   print XXB_FILE "$line_number. assert_load($for_xxb)";
   $wanted_values[1]=$wanted_values[1];#*100; #convert fraction load to percentage load
   unless(eof DATA_FILE){ #unless it the end of the data file
            do{
               &read_msg;        #read a message print "$_[0]:ASSERT_LOAD\n\n";
               $no_read++;
               if(@message==5){
                        $time=&msg_time($message[1]); #get the time of the message
                        if(($time>=$start_time)&&($time<$next_action_time)&&($message[2]=~/^load/)){ #if this time is less than that of
the next test action and more than the start time
                           for ($i=2;$i<4;$i++){
                                    @load_params = @{&get_params($message[$i],'load')};
                                    $load_link=shift(@load_params); #this has the link name
                                    $link_flag=1;
                                    if(@pieces==4){
                                       $slc=pop @pieces;
                                       unless($load_link=~/\Q$slc\E\Z/){
                                                $link_flag=0;}
                                    }
                                    foreach $piece (@pieces){
                                       unless($load_link=~/\Q$piece/){
                                                $link_flag=0;}
                                    }
                                    push @pieces, $slc;
                                    if($link_flag){
                                       if($wanted_values[0] eq $load_params[0]){
                                                $obs_values=$obs_values."NOT FOUND LOAD - $line_number $wanted_link
$wanted_values[0] $wanted_values[1] ACTUAL:$load_params[1] TIME:$time\n"; #this has the list of all load values on the wanted link
which did not matchthe wanted load value
                                                $load_diff=abs($wanted_values[1]-$load_params[1]); #get the absolute diff. between wanted
and actual load values

           if((($load_diff<=$accuracy*$wanted_values[1])||($load_diff<=$patience))&&!$load_found_flag){ #if the diff. is <= the
accuracy
                                                                                                                                      135

                                         #printf POL_FILE "THE FOUND LOAD - %s %s %s %.2f ACTUAL:%.2f
TIME:%s\n",$line_number,$wanted_link,$wanted_values[0],$wanted_values[1],$load_params[1],$time; #print only the matched value to
the POL file
                                         printf "FOUND LOAD - %s %s %s %.2f ACTUAL:%.2f
TIME:%s\n",$line_number,$wanted_link,$wanted_values[0],$wanted_values[1],$load_params[1],$time;
                                         print XXB_FILE "FOUND\n";

                                              #getc; #wait for user response
#                                             print "LOAD: NO_READ= $no_read\n";
                                              $load_found_flag=1;
#                                             return 1;
                                            } #say that we found it
                                     }
                                 }
                          }
                      }
               }
            }until (($time>=$next_action_time)||(eof DATA_FILE)); #try tofind the message until the time of the next message or until the
end of the file
  }
# print "LOAD NOT FOUND: $line_number\n";
  if($obs_values&&!$load_found_flag){
            print XXB_FILE "NOT FOUND\n";
            print MEL_FILE "$line_number. assert_load($for_xxb)\n";
            print POL_FILE $obs_values;
            print "LOAD NOT FOUND @_\n";
            return 0; #if not found, return a 0
  } #If load is not found, then print all the observed values to the POL file
  if(!$obs_values){
            print XXB_FILE "NO MEASUREMENT\n";
            print POL_FILE "$line_number $wanted_link $wanted_values[0] BEGIN TIME:$start_time END TIME:$time LOAD
MEASUREMENT NOT FOUND\n";
            return 2;
  }
            if($load_found_flag){
               $obs_values=~s/NOT //g;
               print POL_FILE $obs_values;
            }
  # print "NOT LOAD: NO_READ= $no_read\n";
}

sub write_timer{
  my ($wait_line,$start_time,$node,$timer_name,$pre_wait_time);
  $wait_line=$_[0]; #the 1st param is the line number of the wait_for
  $start_time=$_[1]; #2nd param is the time at the wait_for
  $timer_name=$_[2]; #the name of the timer ex: T11
  $node=$_[3]; #the node for which the timer value is to be found
  shift(@_);shift(@_);shift(@_);shift(@_); #get rid of the four write_timer params
  unless($while_flag){
            $pre_wait_time=$time;
            $time=$start_time; #should start search only from start_time
            $pre_wait_fp=tell DATA_FILE;
  }
# print "@_\n";
  if(($_[0] eq 'findmsg')||($_[0] eq 'assert_load')){ #the next param should be 'findmsg'
            $func=shift(@_); #get rid of 'findmsg' also
            $result=&{$func}(@_);
            if(($result==1)||($result==3)){ #if the message is found or not found
               $timer_value=$time-$start_time; #timer value is the diff. between the start_time and the time at which the message was found
               if($result==1){
                        printf POL_FILE "%s\t%s\t%s\tSTART:%.3f\tOBS:%.3f", $wait_line,$timer_name,$node,$start_time,$timer_value;
#print the line numb of wait_for, the name of the timer, the name of the node and the observed value of the timer
                        if($while_flag){
                           print POL_FILE " while $next_action_time $time\n";}
                        else{
                           print POL_FILE "\n";}
               }
               if($result==3){
                        unless($while_flag&&$find_flag){
                           print POL_FILE "$wait_line\t$timer_name\t$node - MESSAGE NOT FOUND\n";}
                                                                                                                              136

                  }
                  unless($while_flag){
                            $time=$pre_wait_time;
                            seek DATA_FILE,$pre_wait_fp,0;
                  }
                  return 1;
                }
                elsif($result==2){
                   printf POL_FILE "$wait_line $timer_name $node DATA HIDDEN\n";
                }
    }
    else { #if there is no 'findmsg', this is an error
              print "Error in the write_timer function: use wait_for only with findmsg\n";}
    unless($while_flag){
              seek DATA_FILE,$pre_wait_fp,0;
              $time=$pre_wait_time;
    }
    return 0;
}

sub valid_link{
  my(@link_dir,@pieces,$piece,$link_flag,$slc,$link);
  foreach $link (@monitored_links){
            $link_flag=1;
            @link_dir=split(/\s+/,$link);
            if($_[1] eq '*'){$link_dir[1]='*';}
            if ($_[1] eq $link_dir[1]){
               @pieces=split(/\(/,$_[0]);
               if(@pieces==4){ #If the number of pieces is 4, we have (0) or (1)
                  $slc=pop @pieces; #get the 0) or 1)(last piece) into $slc and remove it from @pieces
                  unless($link_dir[0]=~/\Q$slc\E\Z/){ #unless we see $slc at the end of the link name
                           $link_flag=0;} #unset the link flag
               }
               foreach $piece (@pieces){ #foreach of the rest of the pieces
                  unless($link_dir[0]=~/\Q$piece/){ #unless the piece is seen in the link name
                           $link_flag=0;} #unset the flag
               }
               if($link_flag){return 1;}
    }
  }
  return 0;
}

sub read_msg{
  my ($i,$line,$parameter,$match);
  while($line ne $message_separator){ #reach the message separator
            if (eof DATA_FILE){return 0;} #File has ended message not found
            $line=<DATA_FILE>;
  }
  $match_flag_fp=tell DATA_FILE; #This is the position of the match flag line. This is where we print 'MATCH_FLAG: 1' if needed
  $i=0;
  do{
            $message[$i]=<DATA_FILE>;            #read the next line
            $i++;
  }until ((eof DATA_FILE)||($message[$i-1] eq $message_separator));
  #until the file ends or a message separator is encountered
  $message_end_fp=tell DATA_FILE; #remember where the message ended, we return here after printing 'MATCH_FLAG: 1'

    return 1;
}

sub msg_time{
  $_[0]=~/^[^\s]+/; #The argument to the function is the line which starts with the time of message in seconds
  return $&;
}

sub get_params{
  my (@func_params,$func_line);
  $func_line=$_[0]; #the first argument is the line which contains all the parameters of the message or load measurement
  chomp($func_line); #get rid of the \n
                                                                                                                                     137

    @func_params=split(/\s+/,$func_line); #split across white space to get the parameters

    if($_[1] eq 'message'){ #if the second argument is 'message',
             unless (shift(@func_params) eq 'message'){ #warn if the first thing in the line is not 'message'
                print "This event is not a message:\n@message";}
    }

    elsif($_[1]eq 'load'){ #if $_[1] is 'load'
             unless (shift(@func_params) eq 'load'){ #warn if the first thing in the line is not 'load'
                print "This event is not a load measurement:\n@message";}
    }
    return \@func_params; #return the reference to the parameters array. the word 'message' or 'load' is gotten rid of
}

sub seek_fp{
   my ($wanted_time,$old_fp,$new_fp);
   $wanted_time=$_[0]; #store the wanted time
   if($time>$wanted_time){ #if the time is already more than the wanted time
           print "ERROR: FILE POINTER ALREADY CROSSED THE TEST ACTION TIME\n\n\n";
           seek DATA_FILE,0,0;
   }
   $time=&msg_time($message[1]);
   if($time>$wanted_time){
#          print "ERROR: FILE POINTER ALREADY CROSSED THE TEST ACTION TIME = $wanted_time, PRESENT TIME =
$time \n\n\n";
           seek DATA_FILE,0,0; #do we want this???!!!
   }
   $old_fp = tell DATA_FILE;
   while(($time<=$wanted_time)&&!(eof DATA_FILE)){
           $old_fp=tell DATA_FILE;
           $old_time=$time;
           @message='';
           &read_msg;
           $time=&msg_time($message[1]);
   }
   seek DATA_FILE,$old_fp,0;
   $time=$wanted_time;
}
1;


EVENT SUMMARIZER
#!/usr/local/bin/perl

use FindBin; #This and
use lib $FindBin::Bin; #this are used to tell the program that it should look for the libraries in the program's directory also
use matching_lib;
$|=1;

%stp_timer=(); #hash of hashes with keys1= STP name and keys2=timer name, value =1 if the timer of that STP is seen in the POL - not
necessarily a valid observation value.

%timer_list=(); #hash of hashes of hashes of arrays - keys1=stp name, key2=timer name, key3=start time (or 'while') and the array values
are the observations
$action_number=0; #the number of test actions completed
@test_actions=(); #contains the list of all test actions after reading the POL file
$accuracy=0.20;
$patience=5;
$default_color='#FFFFFF';
$special_color='#FFFFFF';
$header_color='#737cff';
$ta_color='#737cff';
$green='#5faa00';
$red='#cc4817';
$gray='#bebebe';
$no_measure='#777777';

open(POL_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].pol");
open(OUT_FILE,">../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].html");
                                                                                                                        138

print OUT_FILE "<html>\n";
#print OUT_FILE '<body bgcolor="#DDFFFF" text="#000000">'."\n";
print OUT_FILE "<TITLE>$ARGV[0] ANALYSIS</TITLE>"."\n";
print OUT_FILE '<body bgcolor="#000000" text="#000000">'."\n";
print OUT_FILE '<div align="center">'."\n";
print OUT_FILE '<p><font size="+4" color=#FFFFFF>'."Analysis results for $ARGV[0]".'</font></font></p>'."\n";
print OUT_FILE "<p><font size=\"+2\" color=#FFFFFF>ANALYSIS PERFORMED ON: ", scalar(localtime), "</p>\n";
&get_and_write_overall_event_stats();
&get_parameter_observations();
print "ANALYZING INTERMEDIATE RESULTS\n\n";
&write_timer_stats();
&write_exb_analysis();
&write_links_to_files();
print "THE ANALYSIS FOR $ARGV[0] IS COMPLETE\n\n\n";
print "To view the results:\n1. Close this window\n2. Click on 'Show results' in the main window\n\n\n";

###############################################################################


###############################################################################
sub get_and_write_overall_event_stats{
  my($result_color,$result);
  $result_color="#FFFFFF";
  open(ENF_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].enf")||die "Could not open the ENF file $ARGV[0].enf";
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $total_events=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $total_messages=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $unexpected_messages=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $wildcard_matched=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $not_wildcard_matched=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $messages_missing=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $messages_expected=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $loads_missing=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $loads_expected=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $messages_hidden=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $loads_hidden=$&;
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $no_measurement=$&;
  if($unexpected_messages||$messages_missing||$loads_missing){
           $result_color=$red;
           $result="FAIL";}
  elsif($messages_hidden||$loads_hidden){
           $result="INCONCLUSIVE";}
  else{$result="PASS";
            $result_color=$green;
   }
  $severity=(2/3)*($messages_missing+$loads_missing)/($messages_expected-$messages_missing-$messages_hidden+$loads_expected-
$loads_missing-$loads_hidden-$no_measurement)+(1/3)*($unexpected_messages/$not_wildcard_matched);
                                                                                                                               139

   $severity=sprintf("%.2f",$severity);
   print OUT_FILE '<font size="+2" color=#FFFFFF>SUMMARY OF RESULTS: '."<b><font color=$result_color>$result</b></font>,
Severity = $severity</p>\n";
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
   &print_color_code;
   &print_index;
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
   print OUT_FILE '<a name="messages"><b><font size="+2" color=#FFFFFF>MESSAGES</b></font></a><br>'."\n";
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
#table with the results for expected messages
   &table_header("EXPECTED MESSAGES"," ","Missing","Hidden","Matched");
   &table_row("Number",$messages_missing,$messages_hidden,$messages_expected-$messages_missing-$messages_hidden);

&table_row("Percentage",100*$messages_missing/$messages_expected,100*$messages_hidden/$messages_expected,100*($messages_exp
ected-$messages_missing-$messages_hidden)/$messages_expected);
  &table_end;

#table with the results for the actual data
   &table_header("MESSAGES IN ACTUAL DATA"," ","Unexpected","Matched<BR>Without Wildcards","Matched<BR>With
Wildcards");
   &table_row("Number",$unexpected_messages,$not_wildcard_matched,$wildcard_matched);

&table_row("Percentage",100*$unexpected_messages/$total_messages,100*$not_wildcard_matched/$total_messages,100*$wildcard_matc
hed/$total_messages);
  &table_end;

#table with results for expected messages based on message type
   &table_header("EXPECTED MESSAGES BASED ON TYPE"," ","Message Type","Missing","Hidden","Matched");
# $line=<ENF_FILE>;
   while(($line=<ENF_FILE>)=~s/exp_msg_type://){
           @pieces=split(/\s+/,$line);
#          unless($pieces[1]==0){
              $pieces[1]=~s/expected://;
              $pieces[2]=~s/missing://;
              $pieces[3]=~s/hidden://;
              &table_row_two("EXB","Number",$pieces[0],$pieces[2],$pieces[3],$pieces[1]-$pieces[2]-$pieces[3]);
              &table_row("Percentage",100*$pieces[2]/$pieces[1],100*$pieces[3]/$pieces[1],100*($pieces[1]-$pieces[2]-
$pieces[3])/$pieces[1]);
#          }
   }
   &table_end;
#table with results for messages in actual data based on message type
   &table_header("MESSAGES IN ACTUAL DATA BASED ON TYPE"," ","Message Type","Unexpected","Matched <BR>Without
Wildcards","Matched <BR>With Wildcards");
   do{
           $line=~s/actual_msg_type://;
           @pieces=split(/\s+/,$line);
           $pieces[1]=~s/unexpected://;
           $pieces[2]=~s/not_wildcard://;
           $pieces[3]=~s/wildcard://;
           &table_row_two("AER","Number",$pieces[0],$pieces[1],$pieces[2],$pieces[3]);
           &table_row("Percentage",100*$pieces[1]/($pieces[1]+$pieces[2]+$pieces[3]),100*$pieces[2]/($pieces[1]+$pieces[2]+$pieces[3
]),100*$pieces[3]/($pieces[1]+$pieces[2]+$pieces[3]));
  }while(($line=<ENF_FILE>)=~/actual_msg_type:/);
   &table_end;
   print OUT_FILE '<a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";

#table with the results for load measurements
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
   print OUT_FILE '<a name="loads"><b><font size="+2" color=#FFFFFF>LOADS</b></font></a><br>'."\n";
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
   &table_header("EXPECTED LOADS"," ","Mis-matched","Hidden","Matched","No Measurement");
   &table_row("NUMBER",$loads_missing,$loads_hidden,$loads_expected-$loads_missing-$loads_hidden,$no_measurement);
   &table_row("PERCENTAGE",100*$loads_missing/$loads_expected,100*$loads_hidden/$loads_expected,100*($loads_expected-
$loads_missing-$loads_hidden-$no_measurement)/$loads_expected,100*$no_measurement/$loads_expected);
   &table_end;
   print OUT_FILE '<a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";

}
###############################################################################
                                                                                                              140


###############################################################################
#usage: &get_parameter_observations();
#gets the timer observations and load observations from the POL and returns two structures:
#1. %timer_list
#2. %load_obs

sub get_parameter_observations{
  my($action_number);
  $action_number=-1;
  while($line=<POL_FILE>){
           chomp($line);

          if($line=~/LOAD/){ #If it's a load measurement
             $line=~s/^[^\d]+//;
             @pieces=split(/\s+/,$line);
             if ($line=~/MEASUREMENT/){ #there were no measurements in the data during the req. time period
                        push @{$load_obs[$action_number]{$pieces[0]}{"$pieces[1] $pieces[2]"}}, "NO INFO";
             }
             else{
#    line_number link         dir_node exp_load ACTUAL:actual_load TIME:time
#    $pieces[0] $pieces[1] $pieces[2] $pieces[3] $pieces[4]
                       $pieces[4]=~s/ACTUAL://;
                       push @{$load_obs[$action_number]{$pieces[0]}{"$pieces[1] $pieces[2]"}}, $pieces[4];
                       $exp_load[$action_number]{$pieces[0]}{"$pieces[1] $pieces[2]"}= $pieces[3];
             }
          }

           elsif($line=~/Test Action/){ #If it's a test action
#          $line=~s/Test Action - //;
#          $line=~s/TIME.*//;
              $action_number++;
              push @test_actions,$line;
           }

          else{ #If it's a timer observation
             @pieces=split(/\s+/,$line); #split the line across white space
#    waitfor_line_number timer_name stp_name START:time OBS:time               [while start_time end_time]
#    $pieces[0]         $pieces[1] $pieces[2] $pieces[3] $pieces[4]

             $stp_timer{$pieces[2]}{$pieces[1]}=1; #remember the STP and the timer
             if($line=~/while/){ #If the waitfor is in a while loop
                      $pieces[4]=~s/OBS://; #$pieces[4] now has the timer observation value
                      push @{$timer_list{$pieces[2]}{$pieces[1]}{'while'}}, $pieces[4];
                      #add the obs to the array
             }
             else{
                      if(($line=~/HIDDEN/)||($line=~/NOT FOUND/)){
                      }
                      else{
                         $pieces[3]=~s/START://;
                         $pieces[4]=~s/OBS://;
                         push @{$timer_list{$pieces[2]}{$pieces[1]}{$pieces[3]}}, $pieces[4];
                      }
             }
           }
   }
#finished getting the observations

}
###############################################################################

###############################################################################
#analyzing the timer values

sub write_timer_stats{
@all_stps=(keys %stp_timer);
@all_stps=sort @all_stps;

print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
                                                                                                                 141

print OUT_FILE '<a name="timers"><b><font size="+2" color=#FFFFFF>TIMERS</b></font></a><br>'."\n";
print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
unless(@all_stps){
   print OUT_FILE '<b><font size="+2" color=#FFFFFF>NO TIMERS USED IN THIS TEST</font> </b><p>'."\n";
}
foreach $stp (@all_stps){
   $min_table=''; #contains the html code for the table of the minimum values
   $all_table=''; #contains the html code for the table of all values
   print "$stp\n";
   print OUT_FILE '<p><b><font size="+2" color=#FFFFFF>'."$stp".'</font> </b><br>'."\n";
   print OUT_FILE '<hr noshade size=4 width="33%" color=#FFFFFF>'."\n";
   foreach $timer (keys %{$stp_timer{$stp}}){
            print "$timer\n";
            @min_values=();
            @all_values=();
            foreach $start_time (keys %{$timer_list{$stp}{$timer}}){
               @list=@{$timer_list{$stp}{$timer}{$start_time}};
               unless($start_time=~/while/){
                        push @min_values,&get_min(@list);
               }
               push @all_values,@list;
            }
            if(@all_values){
               if(@min_values){
                        $min_timer=&get_min(@min_values);
                        $max_timer=&get_max(@min_values);
                        $avg_timer=&get_avg(@min_values);
                        $avg_timer = sprintf("%.3f", $avg_timer);
                        $samples=$#min_values+1;
                        print "MIN VALUES:\n";
                        printf("MIN=%s MAX=%s AVG=%.3f
SAMPLES:%s\n\n",$min_timer,$max_timer,$avg_timer,$#min_values+1);
                        $min_table=$min_table."<TR BGCOLOR=$default_color><th
BGCOLOR=$special_color>$timer<TH>$avg_timer<TH>$min_timer<TH>$max_timer<TH>$samples\n";
               }
               print "ALL VALUES:\n";
               $min_timer=&get_min(@all_values);
               $max_timer=&get_max(@all_values);
               $avg_timer=&get_avg(@all_values);
               $avg_timer = sprintf("%.3f", $avg_timer);
               $samples=$#all_values+1;
               printf("MIN=%s MAX=%s AVG=%.3f SAMPLES:%s\n\n",$min_timer,$max_timer,$avg_timer,$#all_values+1);
               $all_table=$all_table."<TR BGCOLOR=$default_color><th
BGCOLOR=$special_color>$timer<TH>$avg_timer<TH>$min_timer<TH>$max_timer<TH>$samples\n";
#              &write_timer_table(OUT_FILE,$stp,$timer,"ALL",$min_timer,$max_timer,$avg_timer,$#all_values+1);
            }
            else{
               $all_table=$all_table."<TR BGCOLOR=$default_color><th BGCOLOR=$special_color>$timer<TH COLSPAN=4>NO
DATA\n";
               print "NO INFO\n\n";
            }
   }
   &table_header("All Events","TIMER","AVG","MIN","MAX","SAMPLES");
   print OUT_FILE $all_table;
   print OUT_FILE "</TABLE><p><p>\n";
   if($min_table){
            &table_header("First Event","TIMER","AVG","MIN","MAX","SAMPLES");
            print OUT_FILE $min_table;
            print OUT_FILE "</TABLE>\n";
   }
}
print OUT_FILE '<a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";
print "TIMER ANALYSIS COMPLETE ##########################################\n\n\n\n";

}
###############################################################################

###############################################################################

sub write_exb_analysis{
                                                                                                                            142

  my($previous_action,$line,@uel,@xxb,$time1,$time2);
  local($action);
  $action=0;
  @uel=();
  @xxb=();
  open(XXB_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].xxb");
  open(DATA_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].uel"); #use the name DATA_FILE because we want to
use the matching_lib function DATA_FILE

  $line=<XXB_FILE>;
  chomp($line);
  $previous_action=$line;
  $line=~s/.*TIME: //;
  $time1=$line;
  $action=0;
  print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
  print OUT_FILE '<a name="detailed"><b><font size="+2" color=#FFFFFF>DETAILED ANALYSIS</b></font></a><br>'."\n";
  &table_header(" ","EXPECTED EVENTS","UNEXPECTED EVENTS","OBSERVATIONS");
  while($line=<XXB_FILE>){
           chomp($line);
           if($line=~/TEST ACTION/){
                      $line=~/.*TIME: /;
                      $time2=$';
                      @uel=&get_uel_slice($time1,$time2);
                      $time1=$time2;
                      &write_analysis_slice($previous_action,\@xxb,\@uel);
                      shift @test_actions;
                      $action++;
                      @xxb=();
                      @uel=();
                      $previous_action=$line;
           }
           else{
              push @xxb,$line;
           }
  }
  &write_analysis_slice($previous_action); #ADD THE FINAL 'test_end' line to the table
  &table_end;
  print OUT_FILE '<a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";
  print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
}
###############################################################################

###############################################################################
sub get_uel_slice{
  local(@message);
  my($start_time,$end_time,$previous_fp,@uel);
  $start_time=$_[0];
  $end_time=$_[1];
  @message=();
  $time=$start_time;
  @uel=();

  while(($time<$end_time)&&!eof(DATA_FILE)){
           $previous_fp=tell DATA_FILE;
           &read_msg;
           $time=&msg_time($message[1]); #get the time
           if($time>=$end_time){
              seek DATA_FILE,$previous_fp,0;
              last;
           }
           pop @message;
           shift @message;
           @pieces=split(/\s+/,$message[1]);
           $message[1]=$pieces[0]." link=[$pieces[1]=>$pieces[2]] [OPC=$pieces[3]] [DPC=$pieces[4]] $pieces[5] $pieces[6]
$pieces[7]";
           $message_line=join '<BR>',@message;
           push @uel,$message_line;
  }
  return @uel;
                                                                                    143

}


###############################################################################

###############################################################################
sub write_analysis_slice{
  local($observation,$eb_color,$eb_line,$old_observation,$previous_obs);
  @func_xxb=@{$_[1]};
  @func_uel=@{$_[2]};

    $eb_line=$_[0];
    &color_table_ta($ta_color,$eb_line);
    foreach $uel_line (@func_uel){
             &table_uel($uel_line);
    }
    for ($eb_no=0;$eb_no<@func_xxb;$eb_no++){
             $eb_color=$default_color;
             $observation='';
             $eb_line=$func_xxb[$eb_no];
             &process_eb_line;
             if(($observation eq '0 TIMES')&&($eb_color eq $green)){
                $observation=sprintf("%d TIMES",$previous_obs);
                &color_table_two($eb_color,$eb_line,"",$observation);
             }
             else{
                $old_observation=$observation;
                $old_eb_line=$eb_line;
                $old_eb_color=$eb_color;
                $eb_line=$func_xxb[$eb_no+1];
                &process_eb_line;
                if(($observation eq '0 TIMES')&&($eb_color eq $green)){
                         $old_observation=~/\d+/;
                         $half_number=sprintf("%d",$&/2);
                         $observation=sprintf("%d TIMES",$half_number);
                         $old_observation=sprintf("%d TIMES",$&-$half_number);
                }
                &color_table_two($old_eb_color,$old_eb_line,"",$old_observation);
                $previous_obs=$half_number;
             }
    }
}

###############################################################################
sub process_eb_line{
  if($eb_line=~/findmsg/){
           if($eb_line=~s/NOT FOUND//){
              $eb_color=$red;}
           elsif($eb_line=~s/FOUND//){
              $eb_color=$green;}
           elsif($eb_line=~s/HIDDEN//){
              $eb_color=$gray;}
           if($eb_line=~s/WHILE://){
              $observation=$';
              $eb_line=~s/$observation//;
              $observation=$observation." TIMES";
           }
           return;
  }
  elsif($eb_line=~/assert_load/){
           if($eb_line=~s/HIDDEN//){
              $eb_color=$gray;}
           else{
              &get_load_obs;
           }
           $eb_line=~s/[^)]*\Z//;
  }
}
###############################################################################
#analyzing the loads
                                                                                                                               144

sub get_load_obs{

my($line_number,$copy_line,@pieces,$number_matched,$wanted_load,@load_list,$load_measurement,$load_diff,$number_of_measurem
ents,$match_perc,$min_load,$max_load,$avg_load);

# print "LOAD ANALYSIS BEGIN ############################################\n\n";
# for ($action=0; $action <=$action_number; $action++){
# print "$test_actions[$action]\n";
#          print OUT_FILE '<b><font size="+1">'."$test_actions[$action]".'</font> </b><br><p>'."\n";
  $copy_line=$eb_line;
  $copy_line=~s/^\d+//;
  $line_number=$&;
  $copy_line=~s/\.*\s*assert_load\(//;
  @pieces=split(/,/,$copy_line);
  $link="$pieces[0] $pieces[1]";
#          foreach $line_number (keys %{$load_obs[$action]}){
#             foreach $link (keys %{$load_obs[$action]{$line_number}}){
  $wanted_load=$exp_load[$action]{$line_number}{$link};
  @load_list=@{$load_obs[$action]{$line_number}{$link}};
  $number_matched=0; #total number of measurements that matched the exp. load
  if($load_list[0]=~/NO INFO/){
           $observation="NO MEASUREMENT";
           $eb_color=$no_measure;
#          print "$line_number $link: NO INFO\n";
  }
  else{
           foreach $load_measurement (@load_list){
              $load_diff=abs($load_measurement - $wanted_load);
              if(($load_diff<=$accuracy*$wanted_load)||($load_diff<=$patience)){
                       $number_matched++;
              }
           }
           $number_of_measurements=@load_list;
           $match_perc=100*$number_matched/@load_list;
           $min_load=&get_min(@load_list);
           $max_load=&get_max(@load_list);
           $avg_load=&get_avg(@load_list);
           $match_perc=sprintf("%.0f",$match_perc);
           $avg_load=sprintf("%.2f",$avg_load);
           if($match_perc){
              $eb_color=$green;}
           else{$eb_color=$red;}
           $observation="E=$wanted_load; A=$avg_load; M=$match_perc%<BR>RANGE=[$min_load,$max_load];
S=$number_of_measurements";
#          printf("%s %s MATCH=%.1f MIN=%s MAX=%s EXP=%s AVG=%.2f
SAMPLES:%s\n\n",$line_number,$link,$match_perc,$min_load,$max_load ,$wanted_load,$avg_load,$number_of_measurements);
  }
#             }
#          }
# }
  return;
}

###############################################################################
###############################################################################
sub write_links_to_files{
  print OUT_FILE '<p><a name="outputs"><b><font size="+2" color=#FFFFFF>DATA PRODUCED BY
ANALYSIS</b></font></a><br>'."\n";
  print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
  if(-e "../../../temp/itsweb"){ #if it is tao's web server
             print OUT_FILE '<a href="'."showfile.cgi?mel=yes".'"><font size="+1" color=#FFFFFF>Missing Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."showfile.cgi?uel=yes".'"><font size="+1" color=#FFFFFF>Unexpected Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."showfile.cgi?hel=yes".'"><font size="+1" color=#FFFFFF>Hidden Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."showfile.cgi?pol=yes".'"><font size="+1" color=#FFFFFF>Parameter Observation
List</a><br>'."\n";
             print OUT_FILE '<a href="'."showfile.cgi?mer=yes".'"><font size="+1" color=#FFFFFF>Matched Event Record</a><br>'."\n";
  }
  else{
             print OUT_FILE '<a href="'."$ARGV[0].mel".'"><font size="+1" color=#FFFFFF>Missing Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."$ARGV[0].uel".'"><font size="+1" color=#FFFFFF>Unexpected Event List</a><br>'."\n";
                                                                                                                            145

           print OUT_FILE '<a href="'."$ARGV[0].hel".'"><font size="+1" color=#FFFFFF>Hidden Event List</a><br>'."\n";
           print OUT_FILE '<a href="'."$ARGV[0].pol".'"><font size="+1" color=#FFFFFF>Parameter Observation List</a><br>'."\n";
           print OUT_FILE '<a href="'."$ARGV[0].mer".'"><font size="+1" color=#FFFFFF>Matched Event Record</a><br>'."\n";
    }
    print OUT_FILE '<p><a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";

}

###############################################################################
sub print_color_code{
   print OUT_FILE "<p>Explanation of the color code<br>\n";
   print OUT_FILE "<TABLE BORDER=1 BORDERCOLOR=#000000 CELLSPACING=0>\n<TR
style='background:$default_color'><TH>COLOR<TH>DESCRIPTION\n";
   print OUT_FILE "<TR BGCOLOR=$green><TD>Green<TD>Item was expected and was found in the actual data\n";
   print OUT_FILE "<TR BGCOLOR=$red><TD>Red<TD>Item was unexpected or was missing\n";
   print OUT_FILE "<TR BGCOLOR=$gray><TD>Gray<TD>Item was hidden (link was not monitored)\n";
   print OUT_FILE "<TR BGCOLOR=$no_measure><TD>Dark Gray<TD>Load measurement was not found in the actual data\n";
   print OUT_FILE "</TABLE></p>\n";

}
###############################################################################
sub print_index{
  print OUT_FILE '<p><a name="index"><font size="+2" color=#FFFFFF>INDEX OF REPORT:</a><br>'."\n";
  print OUT_FILE '<a href="#messages"><font size="+1" color=#FFFFFF>MESSAGES</a><br>'."\n";
  print OUT_FILE '<a href="#loads"><font size="+1" color=#FFFFFF>LOADS</a><br>'."\n";
  print OUT_FILE '<a href="#timers"><font size="+1" color=#FFFFFF>TIMERS</a><br>'."\n";
  print OUT_FILE '<a href="#detailed"><font size="+1" color=#FFFFFF>DETAILED ANALYSIS OF EB</a><br>'."\n";
  print OUT_FILE '<a href="#outputs"><font size="+1" color=#FFFFFF>DATA PRODUCED BY ANALYSIS</a><br>'."\n";
}
###############################################################################
###############################################################################
#usage: &table_header(caption,element1,element2,....);
#writes the header of a html table to OUT_FILE

sub table_header{
  my($element);
  print OUT_FILE "<TABLE BORDER=1 BORDERCOLOR=#000000 BORDERCOLORLIGHT=#000000 CELLSPACING=0
>\n<CAPTION><font color=$default_color size=\"+1\">$_[0]</font></CAPTION>\n<TR style='background:$header_color'>";
  shift @_;
  foreach $element (@_){
           print OUT_FILE "<TH>$element";
  }
  print OUT_FILE "\n";
}

###############################################################################
#usage: &table_row_two(type,row_name,element1,element2,....);
#writes one row of a html table to OUT_FILE. type='AER' or 'EXB'
sub table_row_two{
  my($element,$flag);
  $flag=shift @_;
  printf(OUT_FILE "<TR>");
  $element=shift @_;
  print OUT_FILE "<TH style='background:$header_color'>$element";
  $element=shift @_;
  if($_[0]){
            print OUT_FILE "<TD BGCOLOR=$red align=center ROWSPAN=2>$element\n";}
  elsif(($flag eq 'EXB')&&$_[1]){
            print OUT_FILE "<TD BGCOLOR=$gray align=center ROWSPAN=2>$element\n";}
  else{print OUT_FILE "<TD BGCOLOR=$green align=center ROWSPAN=2>$element\n";}
  foreach $element (@_){
            if($element=~/^[\d\.]+\Z/){ #if its a number
               if($element=~/\./){ #if it's a fractional number
                        if($element<=1){ #if it's less than one
                            printf(OUT_FILE "<TD BGCOLOR=%s>%f",$default_color,$element);}
                        else{printf(OUT_FILE "<TD BGCOLOR=%s>%.2f",$default_color,$element);} #if > 1
               }
               else{ #if it's a normal number
                        printf(OUT_FILE "<TD BGCOLOR=%s>%d",$default_color,$element);}
            }
                                                                                                                  146

           else{
              printf(OUT_FILE "<TD BGCOLOR=%s>%s",$default_color,$element);}

    }
    print OUT_FILE "\n";

}

###############################################################################
###############################################################################
#usage: &table_row(row_name,element1,element2,....);
#writes one row of a html table to OUT_FILE
sub table_row{
  my($element);
  printf(OUT_FILE "<TR>");
  $element=shift @_;
  print OUT_FILE "<TH style='background:$header_color'>$element";
  foreach $element (@_){
           if($element=~/^[\d\.]+\Z/){ #if its a number
              if($element=~/\./){ #if it's a fractional number
                       if($element<=1){ #if it's less than one
                           printf(OUT_FILE "<TD BGCOLOR=%s>%.4f",$default_color,$element);}
                       else{printf(OUT_FILE "<TD BGCOLOR=%s>%.2f",$default_color,$element);} #if > 1
              }
              else{ #if it's a normal number
                       printf(OUT_FILE "<TD BGCOLOR=%s>%d",$default_color,$element);}
           }
           else{
              printf(OUT_FILE "<TD BGCOLOR=%s>%s",$default_color,$element);}

    }
    print OUT_FILE "\n";

}

###############################################################################
#usage: &table_end();
#writes the end of a html table to OUT_FILE

sub table_end{
  print OUT_FILE "</table><p>\n";
}

###############################################################################
#usage: &color_table_one(color,element1,element2,....);
#writes one row of a html table to OUT_FILE with element1's background in color
sub color_table_one{
  my($element,$color);
  printf(OUT_FILE "<TR>");
  $color=shift @_;
  $element=shift @_;
  print OUT_FILE "<TD style='background:$color'>$element";
  $element=shift @_;
  if($element ne ''){
           printf(OUT_FILE "<TD BGCOLOR=%s><font size=\"-1\">%s",$color,$element);}
  else{ printf(OUT_FILE "<TD BGCOLOR=%s><BR>",$default_color);}
  print OUT_FILE "\n";
}

###############################################################################
###############################################################################
#usage: &color_table_two(color,element1,element2,....);
#writes one row of a html table to OUT_FILE with element1's background in color and element2 occupying two rows
sub color_table_two{
  my($element,$color);
  printf(OUT_FILE "<TR>");
  $color=shift @_;
  $element=shift @_;
  print OUT_FILE "<TD style='background:$color'>$element";
  $element=shift @_;
                                                                                                                  147

#   if($element ne ''){
  print OUT_FILE "<TD style='background:$color'>$element";
# else{print OUT_FILE "<TD ROWSPAN=2 BGCOLOR=$default_color><BR>";}
  $element=shift @_;
  if($element ne ''){
            printf(OUT_FILE "<TD BGCOLOR=%s><font size=\"-1\">%s",$color,$element);}
  else{printf(OUT_FILE "<TD BGCOLOR=%s><BR>",$color);} #put the <BR> for netscape
  print OUT_FILE "\n";
}

###############################################################################
sub table_uel{
  print OUT_FILE "<TR><TD BGCOLOR=$red><br><TD BGCOLOR=$red>$_[0]<TD BGCOLOR=$red>\n";
}
###############################################################################
#usage: &color_table_two(color,element1,element2,....);
#writes one row of a html table to OUT_FILE with element1's background in color and element2 occupying two rows
sub color_table_ta{
  my($element,$color);
  printf(OUT_FILE "<TR>");
  $color=shift @_;
  $element=shift @_;
  print OUT_FILE "<TD style='background:$color' COLSPAN=3 align='center'><font size=\"+1\"><b>$element</b>";
# foreach $element (@_){
#          print OUT_FILE "<TD style='background:$color'>$element";
# }
  print OUT_FILE "\n";
}

###############################################################################


sub get_min{
  my(@in_array);
  @in_array=@_;
  @in_array= sort by_number @_; #sort all the input values
  return $in_array[0]; #return the minimum value
}

sub get_max{
  my(@in_array);
  @in_array=@_;
  @in_array= sort by_number @_; #sort all the input values
  return $in_array[-1]; #return the maximum value (the last value)
}

sub get_avg{
  my($load,$total_load);
  foreach $load (@_){
           $total_load+=$load;}
  return $total_load/@_; #return the minimum value
}

sub by_number{
  if ($a<$b){
            return -1;
  } elsif ($a==$b){
            return 0;
  } elsif ($a>$b){
            return 1;
  }
}




EVENT SUMMARIZER
#!/usr/local/bin/perl

#USAGE: event_summarizer prefix (ex: unexp_finder test52)
                                                                                                                                    148


#INPUT FILES: matched event record (ex: test52_mer)
#OUTPUT FILES: Unexpected Event List (ex: test52_uel)

use FindBin; #This and
use lib $FindBin::Bin; #this are used to tell the program that it should look for the libraries in the program's directory also
use matching_lib;
use replace_lib;
$|=1;
open(DATA_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].mer")|| die "Could not open the matched event record:
$ARGV[0]".'.mer';
open(UEL_FILE,">../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].uel")|| die "Could not open the file \"$ARGV[0].uel\" for
writing the Unexpected Event List";
open(ENF_FILE,">../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].enf")|| die "Could not open the file \"$ARGV[0].enf\" for
writing the Event Number File";

$no_events=0;
$no_messages=0; #Total number of messages read$n
$no_wild_matched=0; #Total number of messages matched
$no_unmatched=0; #number of unmatched messages
#$end_time=37431; #The time of interest ends here for test52
$end_time=10000000;
%unexpected_msg_types=();
%not_wc_msg_types=();
%wc_msg_types=();
%all_msg_types=();
while(!(eof DATA_FILE)){ #while there are still messages in the file
  @message='';        #clear the message
  if(!&read_msg){last;} #read a new message into @message. Returns 0 if eof of DATA_FILE is reached
  $message[1]=~/^[^\s]+/; #This is where the time of the message will be
# $time=$&; #The matched portion is the time
# if($time>$end_time){last;} #If the time is more than the cutoff time, exit the while loop
  $no_events++;
  if($message[2]=~/^message/){
           $no_messages++; #we have read another message
           @pieces=split(/\s+/,$message[2]);
           $all_msg_types{$pieces[5]}=1;
           unless($wc_msg_types{$pieces[5]}){$wc_msg_types{$pieces[5]}=0;}
           unless($not_wc_msg_types{$pieces[5]}){$not_wc_msg_types{$pieces[5]}=0;}
           unless($unexpected_msg_types{$pieces[5]}){$unexpected_msg_types{$pieces[5]}=0;}

          if($message[0]=~/^MATCH_FLAG: \*/){
             $wc_msg_types{$pieces[5]}++;
             $no_wild_matched++;
          }
          elsif($message[0]=~/^MATCH_FLAG: 0/){ #if the match flag is 0
             $unexpected_msg_types{$pieces[5]}++;
             $no_unmatched++; #found another unmatched event
             unshift @message,$message_separator; #put the message separator in the first line to make it consistent with the AER
             print UEL_FILE @message; #print the unmatched message to the UEL file
          }
          else{
             $not_wc_msg_types{$pieces[5]}++;}
  }

}
close(DATA_FILE);
close(UEL_FILE);

#get information from the XXB, MEL and HEL
open(XXB_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].xxb");
$no_expected_msgs=0; #number of expected messages
$no_expected_loads=0; #number of expected loads
$no_measurement=0;
%expected_msg_types=();
%hidden_msg_types=();
%missing_msg_types=();
while($line=<XXB_FILE>){
  chomp($line);
  if($line=~/findmsg/){
                                                                                                                      149

         $no_expected_msgs++;
         @pieces=split(/,/,$line);
         $pieces[4]=~s/\).*//; #RCT has no other parameters, it will be split as 'RCT)WHILE:8 FOUND'
         $expected_msg_types{$pieces[4]}++;
         $missing_msg_types{$pieces[4]}=0;
         $hidden_msg_types{$pieces[4]}=0;
  }
  elsif($line=~/assert_load/){
            $no_expected_loads++;
            if($line=~/NO MEASUREMENT/){
               $no_measurement++;}
  }
}
close(XXB_FILE);

open(MEL_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].mel");
$no_missing_msgs=0; #number of missing messages
$no_missing_loads=0; #number of missing loads
while($line=<MEL_FILE>){
   chomp($line);
   if($line=~/findmsg/){
             $no_missing_msgs++;
             @pieces=split(/,/,$line);
             $pieces[4]=~s/\).*//;
             $missing_msg_types{$pieces[4]}++;
   }
   elsif($line=~/assert_load/){
             $no_missing_loads++;
   }
}
close(MEL_FILE);

open(HEL_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].hel");
$no_hidden_msgs=0;
$no_hidden_loads=0;
while($line=<HEL_FILE>){
   if($line=~/findmsg/){
             @pieces=split(/,/,$line);
             $hidden_msg_types{$pieces[4]}++;
             $no_hidden_msgs++;
   }
   elsif($line=~/assert_load/){
             $no_hidden_loads++;}
}
close(HEL_FILE);


print ENF_FILE "total events:$no_events\n";
print ENF_FILE "total messages: $no_messages\n";
print ENF_FILE "messages unexpected: $no_unmatched\n";
print ENF_FILE "messages wildcard matched: $no_wild_matched\n";
printf(ENF_FILE "messages matched without wildcard: %d\n",$no_messages-$no_unmatched-$no_wild_matched);
print ENF_FILE "messages missing: $no_missing_msgs\n";
print ENF_FILE "messages expected: $no_expected_msgs\n";
print ENF_FILE "loads missing: $no_missing_loads\n";
print ENF_FILE "loads expected: $no_expected_loads\n";
print ENF_FILE "messages hidden: $no_hidden_msgs\n";
print ENF_FILE "loads hidden: $no_hidden_loads\n";
print ENF_FILE "no measurement: $no_measurement\n";

@msg_types=keys %expected_msg_types;
@msg_types=sort @msg_types;
foreach $msg_type (@msg_types){
   print ENF_FILE
"exp_msg_type:$msg_type\texpected:$expected_msg_types{$msg_type}\tmissing:$missing_msg_types{$msg_type}\thidden:$hidden_msg
_types{$msg_type}\n";
}

@msg_types=keys %all_msg_types;
@msg_types=sort @msg_types;
                                                                                                                                     150

foreach $msg_type (@msg_types){
     print ENF_FILE
"actual_msg_type:$msg_type\tunexpected:$unexpected_msg_types{$msg_type}\tnot_wildcard:$not_wc_msg_types{$msg_type}\twildcard
:$wc_msg_types{$msg_type}\n";
}


#unlink("$ARGV[0].mer");
print "\n\nTotal number of messages: $no_messages \n";
print "Number of Unexpected messages: $no_unmatched \n\n";
print "The Unexpected Event List for $ARGV[0] has been written to the file: $ARGV[0].uel\n\n";



STATISTICAL ANALYZER

#!/usr/local/bin/perl

use FindBin; #This and
use lib $FindBin::Bin; #this are used to tell the program that it should look for the libraries in the program's directory also
use matching_lib;
$|=1;

%stp_timer=(); #hash of hashes with keys1= STP name and keys2=timer name, value =1 if the timer of that STP is seen in the POL - not
necessarily a valid observation value.

%timer_list=(); #hash of hashes of hashes of arrays - keys1=stp name, key2=timer name, key3=start time (or 'while') and the array values
are the observations
$action_number=0; #the number of test actions completed
@test_actions=(); #contains the list of all test actions after reading the POL file
$accuracy=0.20;
$patience=5;
$default_color='#FFFFFF';
$special_color='#FFFFFF';
$header_color='#737cff';
$ta_color='#737cff';
$green='#5faa00';
$red='#cc4817';
$gray='#bebebe';
$no_measure='#777777';

open(POL_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].pol");
open(OUT_FILE,">../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].html");
print OUT_FILE "<html>\n";
#print OUT_FILE '<body bgcolor="#DDFFFF" text="#000000">'."\n";
print OUT_FILE "<TITLE>$ARGV[0] ANALYSIS</TITLE>"."\n";
print OUT_FILE '<body bgcolor="#000000" text="#000000">'."\n";
print OUT_FILE '<div align="center">'."\n";
print OUT_FILE '<p><font size="+4" color=#FFFFFF>'."Analysis results for $ARGV[0]".'</font></font></p>'."\n";
print OUT_FILE "<p><font size=\"+2\" color=#FFFFFF>ANALYSIS PERFORMED ON: ", scalar(localtime), "</p>\n";
&get_and_write_overall_event_stats();
&get_parameter_observations();
print "ANALYZING INTERMEDIATE RESULTS\n\n";
&write_timer_stats();
&write_exb_analysis();
&write_links_to_files();
print "THE ANALYSIS FOR $ARGV[0] IS COMPLETE\n\n\n";
print "To view the results:\n1. Close this window\n2. Click on 'Show results' in the main window\n\n\n";

###############################################################################


###############################################################################
sub get_and_write_overall_event_stats{
  my($result_color,$result);
  $result_color="#FFFFFF";
  open(ENF_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].enf")||die "Could not open the ENF file $ARGV[0].enf";
  $line=<ENF_FILE>;
  $line=~/\d+/;
  $total_events=$&;
                                                                                                                         151

   $line=<ENF_FILE>;
   $line=~/\d+/;
   $total_messages=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $unexpected_messages=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $wildcard_matched=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $not_wildcard_matched=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $messages_missing=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $messages_expected=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $loads_missing=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $loads_expected=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $messages_hidden=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $loads_hidden=$&;
   $line=<ENF_FILE>;
   $line=~/\d+/;
   $no_measurement=$&;
   if($unexpected_messages||$messages_missing||$loads_missing){
            $result_color=$red;
            $result="FAIL";}
   elsif($messages_hidden||$loads_hidden){
            $result="INCONCLUSIVE";}
   else{$result="PASS";
             $result_color=$green;
    }
   $severity=(2/3)*($messages_missing+$loads_missing)/($messages_expected-$messages_missing-$messages_hidden+$loads_expected-
$loads_missing-$loads_hidden-$no_measurement)+(1/3)*($unexpected_messages/$not_wildcard_matched);
   $severity=sprintf("%.2f",$severity);
   print OUT_FILE '<font size="+2" color=#FFFFFF>SUMMARY OF RESULTS: '."<b><font color=$result_color>$result</b></font>,
Severity = $severity</p>\n";
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
   &print_color_code;
   &print_index;
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
   print OUT_FILE '<a name="messages"><b><font size="+2" color=#FFFFFF>MESSAGES</b></font></a><br>'."\n";
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
#table with the results for expected messages
   &table_header("EXPECTED MESSAGES"," ","Missing","Hidden","Matched");
   &table_row("Number",$messages_missing,$messages_hidden,$messages_expected-$messages_missing-$messages_hidden);

&table_row("Percentage",100*$messages_missing/$messages_expected,100*$messages_hidden/$messages_expected,100*($messages_exp
ected-$messages_missing-$messages_hidden)/$messages_expected);
  &table_end;

#table with the results for the actual data
   &table_header("MESSAGES IN ACTUAL DATA"," ","Unexpected","Matched<BR>Without Wildcards","Matched<BR>With
Wildcards");
   &table_row("Number",$unexpected_messages,$not_wildcard_matched,$wildcard_matched);

&table_row("Percentage",100*$unexpected_messages/$total_messages,100*$not_wildcard_matched/$total_messages,100*$wildcard_matc
hed/$total_messages);
  &table_end;

#table with results for expected messages based on message type
                                                                                                                               152

   &table_header("EXPECTED MESSAGES BASED ON TYPE"," ","Message Type","Missing","Hidden","Matched");
# $line=<ENF_FILE>;
   while(($line=<ENF_FILE>)=~s/exp_msg_type://){
           @pieces=split(/\s+/,$line);
#          unless($pieces[1]==0){
              $pieces[1]=~s/expected://;
              $pieces[2]=~s/missing://;
              $pieces[3]=~s/hidden://;
              &table_row_two("EXB","Number",$pieces[0],$pieces[2],$pieces[3],$pieces[1]-$pieces[2]-$pieces[3]);
              &table_row("Percentage",100*$pieces[2]/$pieces[1],100*$pieces[3]/$pieces[1],100*($pieces[1]-$pieces[2]-
$pieces[3])/$pieces[1]);
#          }
   }
   &table_end;
#table with results for messages in actual data based on message type
   &table_header("MESSAGES IN ACTUAL DATA BASED ON TYPE"," ","Message Type","Unexpected","Matched <BR>Without
Wildcards","Matched <BR>With Wildcards");
   do{
           $line=~s/actual_msg_type://;
           @pieces=split(/\s+/,$line);
           $pieces[1]=~s/unexpected://;
           $pieces[2]=~s/not_wildcard://;
           $pieces[3]=~s/wildcard://;
           &table_row_two("AER","Number",$pieces[0],$pieces[1],$pieces[2],$pieces[3]);
           &table_row("Percentage",100*$pieces[1]/($pieces[1]+$pieces[2]+$pieces[3]),100*$pieces[2]/($pieces[1]+$pieces[2]+$pieces[3
]),100*$pieces[3]/($pieces[1]+$pieces[2]+$pieces[3]));
  }while(($line=<ENF_FILE>)=~/actual_msg_type:/);
   &table_end;
   print OUT_FILE '<a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";

#table with the results for load measurements
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
   print OUT_FILE '<a name="loads"><b><font size="+2" color=#FFFFFF>LOADS</b></font></a><br>'."\n";
   print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
   &table_header("EXPECTED LOADS"," ","Mis-matched","Hidden","Matched","No Measurement");
   &table_row("NUMBER",$loads_missing,$loads_hidden,$loads_expected-$loads_missing-$loads_hidden,$no_measurement);
   &table_row("PERCENTAGE",100*$loads_missing/$loads_expected,100*$loads_hidden/$loads_expected,100*($loads_expected-
$loads_missing-$loads_hidden-$no_measurement)/$loads_expected,100*$no_measurement/$loads_expected);
   &table_end;
   print OUT_FILE '<a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";

}
###############################################################################

###############################################################################
#usage: &get_parameter_observations();
#gets the timer observations and load observations from the POL and returns two structures:
#1. %timer_list
#2. %load_obs

sub get_parameter_observations{
  my($action_number);
  $action_number=-1;
  while($line=<POL_FILE>){
           chomp($line);

          if($line=~/LOAD/){ #If it's a load measurement
             $line=~s/^[^\d]+//;
             @pieces=split(/\s+/,$line);
             if ($line=~/MEASUREMENT/){ #there were no measurements in the data during the req. time period
                        push @{$load_obs[$action_number]{$pieces[0]}{"$pieces[1] $pieces[2]"}}, "NO INFO";
             }
             else{
#    line_number link         dir_node exp_load ACTUAL:actual_load TIME:time
#    $pieces[0] $pieces[1] $pieces[2] $pieces[3] $pieces[4]
                       $pieces[4]=~s/ACTUAL://;
                       push @{$load_obs[$action_number]{$pieces[0]}{"$pieces[1] $pieces[2]"}}, $pieces[4];
                       $exp_load[$action_number]{$pieces[0]}{"$pieces[1] $pieces[2]"}= $pieces[3];
             }
          }
                                                                                                             153


           elsif($line=~/Test Action/){ #If it's a test action
#          $line=~s/Test Action - //;
#          $line=~s/TIME.*//;
              $action_number++;
              push @test_actions,$line;
           }

          else{ #If it's a timer observation
             @pieces=split(/\s+/,$line); #split the line across white space
#    waitfor_line_number timer_name stp_name START:time OBS:time               [while start_time end_time]
#    $pieces[0]         $pieces[1] $pieces[2] $pieces[3] $pieces[4]

             $stp_timer{$pieces[2]}{$pieces[1]}=1; #remember the STP and the timer
             if($line=~/while/){ #If the waitfor is in a while loop
                      $pieces[4]=~s/OBS://; #$pieces[4] now has the timer observation value
                      push @{$timer_list{$pieces[2]}{$pieces[1]}{'while'}}, $pieces[4];
                      #add the obs to the array
             }
             else{
                      if(($line=~/HIDDEN/)||($line=~/NOT FOUND/)){
                      }
                      else{
                         $pieces[3]=~s/START://;
                         $pieces[4]=~s/OBS://;
                         push @{$timer_list{$pieces[2]}{$pieces[1]}{$pieces[3]}}, $pieces[4];
                      }
             }
           }
   }
#finished getting the observations

}
###############################################################################

###############################################################################
#analyzing the timer values

sub write_timer_stats{
@all_stps=(keys %stp_timer);
@all_stps=sort @all_stps;

print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
print OUT_FILE '<a name="timers"><b><font size="+2" color=#FFFFFF>TIMERS</b></font></a><br>'."\n";
print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
unless(@all_stps){
   print OUT_FILE '<b><font size="+2" color=#FFFFFF>NO TIMERS USED IN THIS TEST</font> </b><p>'."\n";
}
foreach $stp (@all_stps){
   $min_table=''; #contains the html code for the table of the minimum values
   $all_table=''; #contains the html code for the table of all values
   print "$stp\n";
   print OUT_FILE '<p><b><font size="+2" color=#FFFFFF>'."$stp".'</font> </b><br>'."\n";
   print OUT_FILE '<hr noshade size=4 width="33%" color=#FFFFFF>'."\n";
   foreach $timer (keys %{$stp_timer{$stp}}){
            print "$timer\n";
            @min_values=();
            @all_values=();
            foreach $start_time (keys %{$timer_list{$stp}{$timer}}){
               @list=@{$timer_list{$stp}{$timer}{$start_time}};
               unless($start_time=~/while/){
                       push @min_values,&get_min(@list);
               }
               push @all_values,@list;
            }
            if(@all_values){
               if(@min_values){
                       $min_timer=&get_min(@min_values);
                       $max_timer=&get_max(@min_values);
                       $avg_timer=&get_avg(@min_values);
                                                                                                                    154

                       $avg_timer = sprintf("%.3f", $avg_timer);
                       $samples=$#min_values+1;
                       print "MIN VALUES:\n";
                       printf("MIN=%s MAX=%s AVG=%.3f
SAMPLES:%s\n\n",$min_timer,$max_timer,$avg_timer,$#min_values+1);
                       $min_table=$min_table."<TR BGCOLOR=$default_color><th
BGCOLOR=$special_color>$timer<TH>$avg_timer<TH>$min_timer<TH>$max_timer<TH>$samples\n";
              }
              print "ALL VALUES:\n";
              $min_timer=&get_min(@all_values);
              $max_timer=&get_max(@all_values);
              $avg_timer=&get_avg(@all_values);
              $avg_timer = sprintf("%.3f", $avg_timer);
              $samples=$#all_values+1;
              printf("MIN=%s MAX=%s AVG=%.3f SAMPLES:%s\n\n",$min_timer,$max_timer,$avg_timer,$#all_values+1);
              $all_table=$all_table."<TR BGCOLOR=$default_color><th
BGCOLOR=$special_color>$timer<TH>$avg_timer<TH>$min_timer<TH>$max_timer<TH>$samples\n";
#             &write_timer_table(OUT_FILE,$stp,$timer,"ALL",$min_timer,$max_timer,$avg_timer,$#all_values+1);
           }
           else{
              $all_table=$all_table."<TR BGCOLOR=$default_color><th BGCOLOR=$special_color>$timer<TH COLSPAN=4>NO
DATA\n";
              print "NO INFO\n\n";
           }
   }
   &table_header("All Events","TIMER","AVG","MIN","MAX","SAMPLES");
   print OUT_FILE $all_table;
   print OUT_FILE "</TABLE><p><p>\n";
   if($min_table){
           &table_header("First Event","TIMER","AVG","MIN","MAX","SAMPLES");
           print OUT_FILE $min_table;
           print OUT_FILE "</TABLE>\n";
   }
}
print OUT_FILE '<a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";
print "TIMER ANALYSIS COMPLETE ##########################################\n\n\n\n";

}
###############################################################################

###############################################################################

sub write_exb_analysis{
  my($previous_action,$line,@uel,@xxb,$time1,$time2);
  local($action);
  $action=0;
  @uel=();
  @xxb=();
  open(XXB_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].xxb");
  open(DATA_FILE,"../../DATA/$ARGV[1]/$ARGV[0]/ANALYSIS/$ARGV[0].uel"); #use the name DATA_FILE because we want to
use the matching_lib function DATA_FILE

  $line=<XXB_FILE>;
  chomp($line);
  $previous_action=$line;
  $line=~s/.*TIME: //;
  $time1=$line;
  $action=0;
  print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
  print OUT_FILE '<a name="detailed"><b><font size="+2" color=#FFFFFF>DETAILED ANALYSIS</b></font></a><br>'."\n";
  &table_header(" ","EXPECTED EVENTS","UNEXPECTED EVENTS","OBSERVATIONS");
  while($line=<XXB_FILE>){
           chomp($line);
           if($line=~/TEST ACTION/){
                      $line=~/.*TIME: /;
                      $time2=$';
                      @uel=&get_uel_slice($time1,$time2);
                      $time1=$time2;
                      &write_analysis_slice($previous_action,\@xxb,\@uel);
                      shift @test_actions;
                                                                                                                            155

                     $action++;
                     @xxb=();
                     @uel=();
                     $previous_action=$line;
          }
          else{
             push @xxb,$line;
          }
  }
  &write_analysis_slice($previous_action); #ADD THE FINAL 'test_end' line to the table
  &table_end;
  print OUT_FILE '<a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";
  print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
}
###############################################################################

###############################################################################
sub get_uel_slice{
  local(@message);
  my($start_time,$end_time,$previous_fp,@uel);
  $start_time=$_[0];
  $end_time=$_[1];
  @message=();
  $time=$start_time;
  @uel=();

  while(($time<$end_time)&&!eof(DATA_FILE)){
           $previous_fp=tell DATA_FILE;
           &read_msg;
           $time=&msg_time($message[1]); #get the time
           if($time>=$end_time){
              seek DATA_FILE,$previous_fp,0;
              last;
           }
           pop @message;
           shift @message;
           @pieces=split(/\s+/,$message[1]);
           $message[1]=$pieces[0]." link=[$pieces[1]=>$pieces[2]] [OPC=$pieces[3]] [DPC=$pieces[4]] $pieces[5] $pieces[6]
$pieces[7]";
           $message_line=join '<BR>',@message;
           push @uel,$message_line;
  }
  return @uel;
}


###############################################################################

###############################################################################
sub write_analysis_slice{
  local($observation,$eb_color,$eb_line,$old_observation,$previous_obs);
  @func_xxb=@{$_[1]};
  @func_uel=@{$_[2]};

  $eb_line=$_[0];
  &color_table_ta($ta_color,$eb_line);
  foreach $uel_line (@func_uel){
           &table_uel($uel_line);
  }
  for ($eb_no=0;$eb_no<@func_xxb;$eb_no++){
           $eb_color=$default_color;
           $observation='';
           $eb_line=$func_xxb[$eb_no];
           &process_eb_line;
           if(($observation eq '0 TIMES')&&($eb_color eq $green)){
              $observation=sprintf("%d TIMES",$previous_obs);
              &color_table_two($eb_color,$eb_line,"",$observation);
           }
           else{
              $old_observation=$observation;
                                                                                                                      156

              $old_eb_line=$eb_line;
              $old_eb_color=$eb_color;
              $eb_line=$func_xxb[$eb_no+1];
              &process_eb_line;
              if(($observation eq '0 TIMES')&&($eb_color eq $green)){
                       $old_observation=~/\d+/;
                       $half_number=sprintf("%d",$&/2);
                       $observation=sprintf("%d TIMES",$half_number);
                       $old_observation=sprintf("%d TIMES",$&-$half_number);
              }
              &color_table_two($old_eb_color,$old_eb_line,"",$old_observation);
              $previous_obs=$half_number;
          }
    }
}

###############################################################################
sub process_eb_line{
  if($eb_line=~/findmsg/){
           if($eb_line=~s/NOT FOUND//){
              $eb_color=$red;}
           elsif($eb_line=~s/FOUND//){
              $eb_color=$green;}
           elsif($eb_line=~s/HIDDEN//){
              $eb_color=$gray;}
           if($eb_line=~s/WHILE://){
              $observation=$';
              $eb_line=~s/$observation//;
              $observation=$observation." TIMES";
           }
           return;
  }
  elsif($eb_line=~/assert_load/){
           if($eb_line=~s/HIDDEN//){
              $eb_color=$gray;}
           else{
              &get_load_obs;
           }
           $eb_line=~s/[^)]*\Z//;
  }
}
###############################################################################
#analyzing the loads
sub get_load_obs{

my($line_number,$copy_line,@pieces,$number_matched,$wanted_load,@load_list,$load_measurement,$load_diff,$number_of_measurem
ents,$match_perc,$min_load,$max_load,$avg_load);

# print "LOAD ANALYSIS BEGIN ############################################\n\n";
# for ($action=0; $action <=$action_number; $action++){
# print "$test_actions[$action]\n";
#          print OUT_FILE '<b><font size="+1">'."$test_actions[$action]".'</font> </b><br><p>'."\n";
  $copy_line=$eb_line;
  $copy_line=~s/^\d+//;
  $line_number=$&;
  $copy_line=~s/\.*\s*assert_load\(//;
  @pieces=split(/,/,$copy_line);
  $link="$pieces[0] $pieces[1]";
#          foreach $line_number (keys %{$load_obs[$action]}){
#             foreach $link (keys %{$load_obs[$action]{$line_number}}){
  $wanted_load=$exp_load[$action]{$line_number}{$link};
  @load_list=@{$load_obs[$action]{$line_number}{$link}};
  $number_matched=0; #total number of measurements that matched the exp. load
  if($load_list[0]=~/NO INFO/){
           $observation="NO MEASUREMENT";
           $eb_color=$no_measure;
#          print "$line_number $link: NO INFO\n";
  }
  else{
           foreach $load_measurement (@load_list){
                                                                                                                               157

            $load_diff=abs($load_measurement - $wanted_load);
            if(($load_diff<=$accuracy*$wanted_load)||($load_diff<=$patience)){
                     $number_matched++;
            }
          }
          $number_of_measurements=@load_list;
          $match_perc=100*$number_matched/@load_list;
          $min_load=&get_min(@load_list);
          $max_load=&get_max(@load_list);
          $avg_load=&get_avg(@load_list);
          $match_perc=sprintf("%.0f",$match_perc);
          $avg_load=sprintf("%.2f",$avg_load);
          if($match_perc){
             $eb_color=$green;}
          else{$eb_color=$red;}
          $observation="E=$wanted_load; A=$avg_load; M=$match_perc%<BR>RANGE=[$min_load,$max_load];
S=$number_of_measurements";
#         printf("%s %s MATCH=%.1f MIN=%s MAX=%s EXP=%s AVG=%.2f
SAMPLES:%s\n\n",$line_number,$link,$match_perc,$min_load,$max_load ,$wanted_load,$avg_load,$number_of_measurements);
  }
#            }
#         }
# }
  return;
}

###############################################################################
###############################################################################
sub write_links_to_files{
  print OUT_FILE '<p><a name="outputs"><b><font size="+2" color=#FFFFFF>DATA PRODUCED BY
ANALYSIS</b></font></a><br>'."\n";
  print OUT_FILE '<hr noshade size=7 color='."$header_color>\n";
  if(-e "../../../temp/itsweb"){ #if it is tao's web server
             print OUT_FILE '<a href="'."showfile.cgi?mel=yes".'"><font size="+1" color=#FFFFFF>Missing Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."showfile.cgi?uel=yes".'"><font size="+1" color=#FFFFFF>Unexpected Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."showfile.cgi?hel=yes".'"><font size="+1" color=#FFFFFF>Hidden Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."showfile.cgi?pol=yes".'"><font size="+1" color=#FFFFFF>Parameter Observation
List</a><br>'."\n";
             print OUT_FILE '<a href="'."showfile.cgi?mer=yes".'"><font size="+1" color=#FFFFFF>Matched Event Record</a><br>'."\n";
  }
  else{
             print OUT_FILE '<a href="'."$ARGV[0].mel".'"><font size="+1" color=#FFFFFF>Missing Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."$ARGV[0].uel".'"><font size="+1" color=#FFFFFF>Unexpected Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."$ARGV[0].hel".'"><font size="+1" color=#FFFFFF>Hidden Event List</a><br>'."\n";
             print OUT_FILE '<a href="'."$ARGV[0].pol".'"><font size="+1" color=#FFFFFF>Parameter Observation List</a><br>'."\n";
             print OUT_FILE '<a href="'."$ARGV[0].mer".'"><font size="+1" color=#FFFFFF>Matched Event Record</a><br>'."\n";
  }
  print OUT_FILE '<p><a href="#index"><font size="+1" color=#FFFFFF>BACK TO INDEX</a><br>'."\n";

}

###############################################################################
sub print_color_code{
   print OUT_FILE "<p>Explanation of the color code<br>\n";
   print OUT_FILE "<TABLE BORDER=1 BORDERCOLOR=#000000 CELLSPACING=0>\n<TR
style='background:$default_color'><TH>COLOR<TH>DESCRIPTION\n";
   print OUT_FILE "<TR BGCOLOR=$green><TD>Green<TD>Item was expected and was found in the actual data\n";
   print OUT_FILE "<TR BGCOLOR=$red><TD>Red<TD>Item was unexpected or was missing\n";
   print OUT_FILE "<TR BGCOLOR=$gray><TD>Gray<TD>Item was hidden (link was not monitored)\n";
   print OUT_FILE "<TR BGCOLOR=$no_measure><TD>Dark Gray<TD>Load measurement was not found in the actual data\n";
   print OUT_FILE "</TABLE></p>\n";

}
###############################################################################
sub print_index{
  print OUT_FILE '<p><a name="index"><font size="+2" color=#FFFFFF>INDEX OF REPORT:</a><br>'."\n";
  print OUT_FILE '<a href="#messages"><font size="+1" color=#FFFFFF>MESSAGES</a><br>'."\n";
  print OUT_FILE '<a href="#loads"><font size="+1" color=#FFFFFF>LOADS</a><br>'."\n";
  print OUT_FILE '<a href="#timers"><font size="+1" color=#FFFFFF>TIMERS</a><br>'."\n";
  print OUT_FILE '<a href="#detailed"><font size="+1" color=#FFFFFF>DETAILED ANALYSIS OF EB</a><br>'."\n";
                                                                                                                     158

  print OUT_FILE '<a href="#outputs"><font size="+1" color=#FFFFFF>DATA PRODUCED BY ANALYSIS</a><br>'."\n";
}
###############################################################################
###############################################################################
#usage: &table_header(caption,element1,element2,....);
#writes the header of a html table to OUT_FILE

sub table_header{
  my($element);
  print OUT_FILE "<TABLE BORDER=1 BORDERCOLOR=#000000 BORDERCOLORLIGHT=#000000 CELLSPACING=0
>\n<CAPTION><font color=$default_color size=\"+1\">$_[0]</font></CAPTION>\n<TR style='background:$header_color'>";
  shift @_;
  foreach $element (@_){
           print OUT_FILE "<TH>$element";
  }
  print OUT_FILE "\n";
}

###############################################################################
#usage: &table_row_two(type,row_name,element1,element2,....);
#writes one row of a html table to OUT_FILE. type='AER' or 'EXB'
sub table_row_two{
  my($element,$flag);
  $flag=shift @_;
  printf(OUT_FILE "<TR>");
  $element=shift @_;
  print OUT_FILE "<TH style='background:$header_color'>$element";
  $element=shift @_;
  if($_[0]){
            print OUT_FILE "<TD BGCOLOR=$red align=center ROWSPAN=2>$element\n";}
  elsif(($flag eq 'EXB')&&$_[1]){
            print OUT_FILE "<TD BGCOLOR=$gray align=center ROWSPAN=2>$element\n";}
  else{print OUT_FILE "<TD BGCOLOR=$green align=center ROWSPAN=2>$element\n";}
  foreach $element (@_){
            if($element=~/^[\d\.]+\Z/){ #if its a number
               if($element=~/\./){ #if it's a fractional number
                        if($element<=1){ #if it's less than one
                            printf(OUT_FILE "<TD BGCOLOR=%s>%f",$default_color,$element);}
                        else{printf(OUT_FILE "<TD BGCOLOR=%s>%.2f",$default_color,$element);} #if > 1
               }
               else{ #if it's a normal number
                        printf(OUT_FILE "<TD BGCOLOR=%s>%d",$default_color,$element);}
            }
            else{
               printf(OUT_FILE "<TD BGCOLOR=%s>%s",$default_color,$element);}

    }
    print OUT_FILE "\n";

}

###############################################################################
###############################################################################
#usage: &table_row(row_name,element1,element2,....);
#writes one row of a html table to OUT_FILE
sub table_row{
  my($element);
  printf(OUT_FILE "<TR>");
  $element=shift @_;
  print OUT_FILE "<TH style='background:$header_color'>$element";
  foreach $element (@_){
           if($element=~/^[\d\.]+\Z/){ #if its a number
              if($element=~/\./){ #if it's a fractional number
                       if($element<=1){ #if it's less than one
                           printf(OUT_FILE "<TD BGCOLOR=%s>%.4f",$default_color,$element);}
                       else{printf(OUT_FILE "<TD BGCOLOR=%s>%.2f",$default_color,$element);} #if > 1
              }
              else{ #if it's a normal number
                       printf(OUT_FILE "<TD BGCOLOR=%s>%d",$default_color,$element);}
           }
                                                                                                                  159

           else{
              printf(OUT_FILE "<TD BGCOLOR=%s>%s",$default_color,$element);}

    }
    print OUT_FILE "\n";

}

###############################################################################
#usage: &table_end();
#writes the end of a html table to OUT_FILE

sub table_end{
  print OUT_FILE "</table><p>\n";
}

###############################################################################
#usage: &color_table_one(color,element1,element2,....);
#writes one row of a html table to OUT_FILE with element1's background in color
sub color_table_one{
  my($element,$color);
  printf(OUT_FILE "<TR>");
  $color=shift @_;
  $element=shift @_;
  print OUT_FILE "<TD style='background:$color'>$element";
  $element=shift @_;
  if($element ne ''){
           printf(OUT_FILE "<TD BGCOLOR=%s><font size=\"-1\">%s",$color,$element);}
  else{ printf(OUT_FILE "<TD BGCOLOR=%s><BR>",$default_color);}
  print OUT_FILE "\n";
}

###############################################################################
###############################################################################
#usage: &color_table_two(color,element1,element2,....);
#writes one row of a html table to OUT_FILE with element1's background in color and element2 occupying two rows
sub color_table_two{
  my($element,$color);
  printf(OUT_FILE "<TR>");
  $color=shift @_;
  $element=shift @_;
  print OUT_FILE "<TD style='background:$color'>$element";
  $element=shift @_;
# if($element ne ''){
  print OUT_FILE "<TD style='background:$color'>$element";
# else{print OUT_FILE "<TD ROWSPAN=2 BGCOLOR=$default_color><BR>";}
  $element=shift @_;
  if($element ne ''){
           printf(OUT_FILE "<TD BGCOLOR=%s><font size=\"-1\">%s",$color,$element);}
  else{printf(OUT_FILE "<TD BGCOLOR=%s><BR>",$color);} #put the <BR> for netscape
  print OUT_FILE "\n";
}

###############################################################################
sub table_uel{
  print OUT_FILE "<TR><TD BGCOLOR=$red><br><TD BGCOLOR=$red>$_[0]<TD BGCOLOR=$red>\n";
}
###############################################################################
#usage: &color_table_two(color,element1,element2,....);
#writes one row of a html table to OUT_FILE with element1's background in color and element2 occupying two rows
sub color_table_ta{
  my($element,$color);
  printf(OUT_FILE "<TR>");
  $color=shift @_;
  $element=shift @_;
  print OUT_FILE "<TD style='background:$color' COLSPAN=3 align='center'><font size=\"+1\"><b>$element</b>";
# foreach $element (@_){
#          print OUT_FILE "<TD style='background:$color'>$element";
# }
  print OUT_FILE "\n";
                                                                                  160

}

###############################################################################


sub get_min{
  my(@in_array);
  @in_array=@_;
  @in_array= sort by_number @_; #sort all the input values
  return $in_array[0]; #return the minimum value
}

sub get_max{
  my(@in_array);
  @in_array=@_;
  @in_array= sort by_number @_; #sort all the input values
  return $in_array[-1]; #return the maximum value (the last value)
}

sub get_avg{
  my($load,$total_load);
  foreach $load (@_){
           $total_load+=$load;}
  return $total_load/@_; #return the minimum value
}

sub by_number{
  if ($a<$b){
            return -1;
  } elsif ($a==$b){
            return 0;
  } elsif ($a>$b){
            return 1;
  }
}
                                                                                   161


                                     References

[1]   Request for Comments: 1812, Requirements for IP Version 4 Routers; Network
      Working Group, IETF, June 1995


[2]   Bell Communications Research Specification of Signaling System Number 7, GR-
      246-CORE, DECEMBER 1998

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:2
posted:1/31/2012
language:
pages:169
jianghongl jianghongl http://
About